mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 06:40:01 +08:00
[analyzer] Emit IssueHash in SARIF (#159445)
This change adds two new properties to each `result` object in the SARIF log: `partialFingerprints`: Contains the "issue hash" that the analyzer already generates for each result, which can help identify a result across runs even if surrounding code changes. `hostedViewUri`: If running with `-analyzer-format=sarif-html`, this property will now be emitted with the `file:` URL of the generated HTML report for that result. Along the way, I discovered an existing bug where the HTML diagnostic consumer does not record the path to the generated report if another compilation already created that report. This caused both the SARIF and Plist consumers to be missing the link to the file in all but one of the compilations in case of a warning in a header file. I added a new test to ensure that the generated SARIF for each compilation contains the property. Finally, I made a few changes to the `normalize_sarif` processing in the tests. I switched to `sed` to allow substitutions. The normalization now removes directory components from `file:` URLs, replaces the `length` property of the source file with a constant `-1`, and puts placeholders in the values of the `version` properties rather than just deleting them. The URL transformation in particular lets us verify that the right filename is generated for each HTML report. Fixes #158159 rdar://160410408
This commit is contained in:
@@ -885,6 +885,10 @@ public:
|
||||
return UniqueingDecl;
|
||||
}
|
||||
|
||||
/// Get a hash that identifies the issue.
|
||||
SmallString<32> getIssueHash(const SourceManager &SrcMgr,
|
||||
const LangOptions &LangOpts) const;
|
||||
|
||||
void flattenLocations() {
|
||||
Loc.flatten();
|
||||
for (const auto &I : pathImpl)
|
||||
|
||||
@@ -322,6 +322,8 @@ class SarifResult {
|
||||
uint32_t RuleIdx;
|
||||
std::string RuleId;
|
||||
std::string DiagnosticMessage;
|
||||
std::string HostedViewerURI;
|
||||
llvm::SmallDenseMap<StringRef, std::string, 4> PartialFingerprints;
|
||||
llvm::SmallVector<CharSourceRange, 8> Locations;
|
||||
llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
|
||||
std::optional<SarifResultLevel> LevelOverride;
|
||||
@@ -347,6 +349,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult setHostedViewerURI(llvm::StringRef URI) {
|
||||
HostedViewerURI = URI.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
|
||||
#ifndef NDEBUG
|
||||
for (const auto &Loc : DiagLocs) {
|
||||
@@ -366,6 +373,12 @@ public:
|
||||
LevelOverride = TheLevel;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult addPartialFingerprint(llvm::StringRef key,
|
||||
llvm::StringRef value) {
|
||||
PartialFingerprints[key] = value;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// This class handles creating a valid SARIF document given various input
|
||||
@@ -475,6 +488,8 @@ public:
|
||||
/// reported diagnostics, resulting in an expensive call.
|
||||
llvm::json::Object createDocument();
|
||||
|
||||
static std::string fileNameToURI(llvm::StringRef Filename);
|
||||
|
||||
private:
|
||||
/// Source Manager to use for the current SARIF document.
|
||||
const SourceManager &SourceMgr;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/IssueHash.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
@@ -1075,6 +1076,19 @@ unsigned PathDiagnostic::full_size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
SmallString<32>
|
||||
PathDiagnostic::getIssueHash(const SourceManager &SrcMgr,
|
||||
const LangOptions &LangOpts) const {
|
||||
PathDiagnosticLocation UPDLoc = getUniqueingLoc();
|
||||
FullSourceLoc FullLoc(
|
||||
SrcMgr.getExpansionLoc(UPDLoc.isValid() ? UPDLoc.asLocation()
|
||||
: getLocation().asLocation()),
|
||||
SrcMgr);
|
||||
|
||||
return clang::getIssueHash(FullLoc, getCheckerName(), getBugType(),
|
||||
getDeclWithIssue(), LangOpts);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FoldingSet profiling methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -67,7 +67,7 @@ static std::string percentEncodeURICharacter(char C) {
|
||||
/// \param Filename The filename to be represented as URI.
|
||||
///
|
||||
/// \return RFC3986 URI representing the input file name.
|
||||
static std::string fileNameToURI(StringRef Filename) {
|
||||
std::string SarifDocumentWriter::fileNameToURI(StringRef Filename) {
|
||||
SmallString<32> Ret = StringRef("file://");
|
||||
|
||||
// Get the root name to see if it has a URI authority.
|
||||
@@ -391,6 +391,11 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
|
||||
json::Object Ret{{"message", createMessage(Result.DiagnosticMessage)},
|
||||
{"ruleIndex", static_cast<int64_t>(RuleIdx)},
|
||||
{"ruleId", Rule.Id}};
|
||||
|
||||
if (!Result.HostedViewerURI.empty()) {
|
||||
Ret["hostedViewerUri"] = Result.HostedViewerURI;
|
||||
}
|
||||
|
||||
if (!Result.Locations.empty()) {
|
||||
json::Array Locs;
|
||||
for (auto &Range : Result.Locations) {
|
||||
@@ -398,6 +403,15 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
|
||||
}
|
||||
Ret["locations"] = std::move(Locs);
|
||||
}
|
||||
|
||||
if (!Result.PartialFingerprints.empty()) {
|
||||
json::Object fingerprints = {};
|
||||
for (auto &pair : Result.PartialFingerprints) {
|
||||
fingerprints[pair.first] = pair.second;
|
||||
}
|
||||
Ret["partialFingerprints"] = std::move(fingerprints);
|
||||
}
|
||||
|
||||
if (!Result.ThreadFlows.empty())
|
||||
Ret["codeFlows"] = json::Array{createCodeFlow(Result.ThreadFlows)};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "HTMLDiagnostics.h"
|
||||
#include "PlistDiagnostics.h"
|
||||
#include "SarifDiagnostics.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
|
||||
FilesMade *filesMade) override;
|
||||
|
||||
StringRef getName() const override { return "HTMLDiagnostics"; }
|
||||
StringRef getName() const override { return HTML_DIAGNOSTICS_NAME; }
|
||||
|
||||
bool supportsCrossFileDiagnostics() const override {
|
||||
return SupportsCrossFileDiagnostics;
|
||||
@@ -254,18 +255,6 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
|
||||
ReportDiag(*Diag, filesMade);
|
||||
}
|
||||
|
||||
static llvm::SmallString<32> getIssueHash(const PathDiagnostic &D,
|
||||
const Preprocessor &PP) {
|
||||
SourceManager &SMgr = PP.getSourceManager();
|
||||
PathDiagnosticLocation UPDLoc = D.getUniqueingLoc();
|
||||
FullSourceLoc L(SMgr.getExpansionLoc(UPDLoc.isValid()
|
||||
? UPDLoc.asLocation()
|
||||
: D.getLocation().asLocation()),
|
||||
SMgr);
|
||||
return getIssueHash(L, D.getCheckerName(), D.getBugType(),
|
||||
D.getDeclWithIssue(), PP.getLangOpts());
|
||||
}
|
||||
|
||||
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
|
||||
FilesMade *filesMade) {
|
||||
// Create the HTML directory if it is missing.
|
||||
@@ -310,7 +299,8 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
|
||||
}
|
||||
}
|
||||
|
||||
SmallString<32> IssueHash = getIssueHash(D, PP);
|
||||
SmallString<32> IssueHash =
|
||||
D.getIssueHash(PP.getSourceManager(), PP.getLangOpts());
|
||||
auto [It, IsNew] = EmittedHashes.insert(IssueHash);
|
||||
if (!IsNew) {
|
||||
// We've already emitted a duplicate issue. It'll get overwritten anyway.
|
||||
@@ -369,6 +359,12 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
|
||||
if (EC != llvm::errc::file_exists) {
|
||||
llvm::errs() << "warning: could not create file in '" << Directory
|
||||
<< "': " << EC.message() << '\n';
|
||||
} else if (filesMade) {
|
||||
// Record that we created the file so that it gets referenced in the
|
||||
// plist and SARIF reports for every translation unit that found the
|
||||
// issue.
|
||||
filesMade->addDiagnostic(D, getName(),
|
||||
llvm::sys::path::filename(ResultPath));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -679,8 +675,8 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic &D, Rewriter &R,
|
||||
|
||||
os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
|
||||
|
||||
os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT " << getIssueHash(D, PP)
|
||||
<< " -->\n";
|
||||
os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT "
|
||||
<< D.getIssueHash(PP.getSourceManager(), PP.getLangOpts()) << " -->\n";
|
||||
|
||||
os << "\n<!-- BUGLINE "
|
||||
<< LineNumber
|
||||
|
||||
14
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h
Normal file
14
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//==- HTMLDiagnostics.h - HTML Diagnostics for Paths ---------------*- C++ -*-//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_HTMLDIAGNOSTICS_H
|
||||
#define LLVM_CLANG_LIB_STATICANALYZER_CORE_HTMLDIAGNOSTICS_H
|
||||
|
||||
#define HTML_DIAGNOSTICS_NAME "HTMLDiagnostics"
|
||||
|
||||
#endif
|
||||
@@ -706,13 +706,11 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
|
||||
o << " <key>issue_hash_content_of_line_in_context</key>";
|
||||
PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
|
||||
FullSourceLoc L(SM.getExpansionLoc(UPDLoc.isValid()
|
||||
? UPDLoc.asLocation()
|
||||
: D->getLocation().asLocation()),
|
||||
? UPDLoc.asLocation()
|
||||
: D->getLocation().asLocation()),
|
||||
SM);
|
||||
const Decl *DeclWithIssue = D->getDeclWithIssue();
|
||||
EmitString(o, getIssueHash(L, D->getCheckerName(), D->getBugType(),
|
||||
DeclWithIssue, LangOpts))
|
||||
<< '\n';
|
||||
|
||||
EmitString(o, D->getIssueHash(SM, LangOpts)) << '\n';
|
||||
|
||||
// Output information about the semantic context where
|
||||
// the issue occurred.
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SarifDiagnostics.h"
|
||||
#include "HTMLDiagnostics.h"
|
||||
#include "clang/Analysis/IssueHash.h"
|
||||
#include "clang/Analysis/MacroExpansionContext.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Basic/Sarif.h"
|
||||
@@ -31,12 +33,13 @@ namespace {
|
||||
class SarifDiagnostics : public PathDiagnosticConsumer {
|
||||
std::string OutputFile;
|
||||
const LangOptions &LO;
|
||||
const SourceManager &SM;
|
||||
SarifDocumentWriter SarifWriter;
|
||||
|
||||
public:
|
||||
SarifDiagnostics(const std::string &Output, const LangOptions &LO,
|
||||
const SourceManager &SM)
|
||||
: OutputFile(Output), LO(LO), SarifWriter(SM) {}
|
||||
: OutputFile(Output), LO(LO), SM(SM), SarifWriter(SM) {}
|
||||
~SarifDiagnostics() override = default;
|
||||
|
||||
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
|
||||
@@ -46,6 +49,11 @@ public:
|
||||
PathGenerationScheme getGenerationScheme() const override { return Minimal; }
|
||||
bool supportsLogicalOpControlFlow() const override { return true; }
|
||||
bool supportsCrossFileDiagnostics() const override { return true; }
|
||||
|
||||
private:
|
||||
SarifResult createResult(const PathDiagnostic *Diag,
|
||||
const StringMap<uint32_t> &RuleMapping,
|
||||
const LangOptions &LO, FilesMade *FM);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
@@ -173,9 +181,12 @@ createRuleMapping(const std::vector<const PathDiagnostic *> &Diags,
|
||||
return RuleMapping;
|
||||
}
|
||||
|
||||
static SarifResult createResult(const PathDiagnostic *Diag,
|
||||
const StringMap<uint32_t> &RuleMapping,
|
||||
const LangOptions &LO) {
|
||||
static const llvm::StringRef IssueHashKey = "clang/issueHash/v1";
|
||||
|
||||
SarifResult
|
||||
SarifDiagnostics::createResult(const PathDiagnostic *Diag,
|
||||
const StringMap<uint32_t> &RuleMapping,
|
||||
const LangOptions &LO, FilesMade *FM) {
|
||||
|
||||
StringRef CheckName = Diag->getCheckerName();
|
||||
uint32_t RuleIdx = RuleMapping.lookup(CheckName);
|
||||
@@ -183,17 +194,40 @@ static SarifResult createResult(const PathDiagnostic *Diag,
|
||||
Diag->getLocation().asRange(), Diag->getLocation().getManager(), LO);
|
||||
|
||||
SmallVector<ThreadFlow, 8> Flows = createThreadFlows(Diag, LO);
|
||||
|
||||
auto IssueHash = Diag->getIssueHash(SM, LO);
|
||||
|
||||
std::string HtmlReportURL;
|
||||
if (FM && !FM->empty()) {
|
||||
// Find the HTML report that was generated for this issue, if one exists.
|
||||
PDFileEntry::ConsumerFiles *Files = FM->getFiles(*Diag);
|
||||
if (Files) {
|
||||
auto HtmlFile =
|
||||
std::find_if(Files->cbegin(), Files->cend(), [](auto &File) {
|
||||
return File.first == HTML_DIAGNOSTICS_NAME;
|
||||
});
|
||||
if (HtmlFile != Files->cend()) {
|
||||
SmallString<128> HtmlReportPath =
|
||||
llvm::sys::path::parent_path(OutputFile);
|
||||
llvm::sys::path::append(HtmlReportPath, HtmlFile->second);
|
||||
HtmlReportURL = SarifDocumentWriter::fileNameToURI(HtmlReportPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Result = SarifResult::create(RuleIdx)
|
||||
.setRuleId(CheckName)
|
||||
.setDiagnosticMessage(Diag->getVerboseDescription())
|
||||
.setDiagnosticLevel(SarifResultLevel::Warning)
|
||||
.setLocations({Range})
|
||||
.addPartialFingerprint(IssueHashKey, IssueHash)
|
||||
.setHostedViewerURI(HtmlReportURL)
|
||||
.setThreadFlows(Flows);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void SarifDiagnostics::FlushDiagnosticsImpl(
|
||||
std::vector<const PathDiagnostic *> &Diags, FilesMade *) {
|
||||
std::vector<const PathDiagnostic *> &Diags, FilesMade *FM) {
|
||||
// We currently overwrite the file if it already exists. However, it may be
|
||||
// useful to add a feature someday that allows the user to append a run to an
|
||||
// existing SARIF file. One danger from that approach is that the size of the
|
||||
@@ -210,7 +244,7 @@ void SarifDiagnostics::FlushDiagnosticsImpl(
|
||||
SarifWriter.createRun("clang", "clang static analyzer", ToolVersion);
|
||||
StringMap<uint32_t> RuleMapping = createRuleMapping(Diags, SarifWriter);
|
||||
for (const PathDiagnostic *D : Diags) {
|
||||
SarifResult Result = createResult(D, RuleMapping, LO);
|
||||
SarifResult Result = createResult(D, RuleMapping, LO, FM);
|
||||
SarifWriter.appendResult(Result);
|
||||
}
|
||||
auto Document = SarifWriter.createDocument();
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"length": 425,
|
||||
"length": -1,
|
||||
"location": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-diagnostics-taint-test.c"
|
||||
},
|
||||
"mimeType": "text/plain",
|
||||
"roles": [
|
||||
@@ -31,6 +32,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-diagnostics-taint-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 6,
|
||||
@@ -50,6 +52,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-diagnostics-taint-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 18,
|
||||
@@ -71,6 +74,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-diagnostics-taint-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 18,
|
||||
@@ -84,6 +88,9 @@
|
||||
"message": {
|
||||
"text": "tainted"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "5c964815b8d6db3989bacdd308e657d0"
|
||||
},
|
||||
"ruleId": "debug.TaintTest",
|
||||
"ruleIndex": 0
|
||||
}
|
||||
@@ -108,8 +115,10 @@
|
||||
"name": "debug.TaintTest"
|
||||
}
|
||||
],
|
||||
"version": "[clang version]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": "[SARIF version]"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"length": 1152,
|
||||
"length": -1,
|
||||
"location": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"mimeType": "text/plain",
|
||||
"roles": [
|
||||
@@ -31,6 +32,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 6,
|
||||
@@ -50,6 +52,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 18,
|
||||
@@ -65,12 +68,14 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-5c9648.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 18,
|
||||
@@ -84,6 +89,9 @@
|
||||
"message": {
|
||||
"text": "tainted"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "5c964815b8d6db3989bacdd308e657d0"
|
||||
},
|
||||
"ruleId": "debug.TaintTest",
|
||||
"ruleIndex": 0
|
||||
},
|
||||
@@ -102,6 +110,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 6,
|
||||
@@ -121,6 +130,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 12,
|
||||
@@ -140,6 +150,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 9,
|
||||
@@ -155,12 +166,14 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-256f65.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 9,
|
||||
@@ -174,6 +187,9 @@
|
||||
"message": {
|
||||
"text": "Called function pointer is an uninitialized pointer value"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "256f6502719de88bece09a676d4102c6"
|
||||
},
|
||||
"ruleId": "core.CallAndMessage",
|
||||
"ruleIndex": 1
|
||||
},
|
||||
@@ -192,6 +208,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 13,
|
||||
@@ -211,6 +228,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 3,
|
||||
@@ -229,6 +247,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 14,
|
||||
@@ -243,12 +262,14 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-91023b.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 14,
|
||||
@@ -261,6 +282,9 @@
|
||||
"message": {
|
||||
"text": "Division by zero"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "91023b85b7e0ff79f11ab603e63cfa58"
|
||||
},
|
||||
"ruleId": "core.DivideZero",
|
||||
"ruleIndex": 2
|
||||
},
|
||||
@@ -279,6 +303,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 24,
|
||||
@@ -298,6 +323,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 12,
|
||||
@@ -317,6 +343,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 3,
|
||||
@@ -335,6 +362,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 12,
|
||||
@@ -349,12 +377,14 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-b18daa.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 12,
|
||||
@@ -367,6 +397,9 @@
|
||||
"message": {
|
||||
"text": "Potential leak of memory pointed to by 'mem'"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "b18daabce2816b9efb6afffaa64ca9f9"
|
||||
},
|
||||
"ruleId": "unix.Malloc",
|
||||
"ruleIndex": 3
|
||||
},
|
||||
@@ -385,6 +418,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 12,
|
||||
@@ -404,6 +438,7 @@
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 20,
|
||||
@@ -418,12 +453,14 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-4e5361.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-diagnostic-test.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 20,
|
||||
@@ -436,6 +473,9 @@
|
||||
"message": {
|
||||
"text": "Division by zero"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "4e53611783411e0dae06a4084b00281c"
|
||||
},
|
||||
"ruleId": "core.DivideZero",
|
||||
"ruleIndex": 2
|
||||
}
|
||||
@@ -499,8 +539,10 @@
|
||||
"name": "unix.Malloc"
|
||||
}
|
||||
],
|
||||
"version": "[clang version]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": "[SARIF version]"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
|
||||
"runs": [
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"length": -1,
|
||||
"location": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-file-diagnostics.c"
|
||||
},
|
||||
"mimeType": "text/plain",
|
||||
"roles": [
|
||||
"resultFile"
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "unicodeCodePoints",
|
||||
"results": [
|
||||
{
|
||||
"codeFlows": [
|
||||
{
|
||||
"threadFlows": [
|
||||
{
|
||||
"locations": [
|
||||
{
|
||||
"importance": "important",
|
||||
"location": {
|
||||
"message": {
|
||||
"text": "Assuming 'p' is null"
|
||||
},
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-file-diagnostics.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 7,
|
||||
"startColumn": 7,
|
||||
"startLine": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"importance": "unimportant",
|
||||
"location": {
|
||||
"message": {
|
||||
"text": "Taking false branch"
|
||||
},
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-file-diagnostics.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 3,
|
||||
"startColumn": 3,
|
||||
"startLine": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"importance": "essential",
|
||||
"location": {
|
||||
"message": {
|
||||
"text": "Dereference of null pointer (loaded from variable 'p')"
|
||||
},
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-file-diagnostics.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 14,
|
||||
"endLine": 11,
|
||||
"startColumn": 12,
|
||||
"startLine": 11
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"hostedViewerUri": "file:///[...]/report-d03238.html",
|
||||
"level": "warning",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"index": 0,
|
||||
"uri": "file:///[...]/sarif-multi-file-diagnostics.c"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 14,
|
||||
"endLine": 11,
|
||||
"startColumn": 12,
|
||||
"startLine": 11
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": {
|
||||
"text": "Dereference of null pointer (loaded from variable 'p')"
|
||||
},
|
||||
"partialFingerprints": {
|
||||
"clang/issueHash/v1": "d0323824ffaf9fee78b866e18d300fda"
|
||||
},
|
||||
"ruleId": "core.NullDereference",
|
||||
"ruleIndex": 0
|
||||
}
|
||||
],
|
||||
"tool": {
|
||||
"driver": {
|
||||
"fullName": "clang static analyzer",
|
||||
"informationUri": "https://clang.llvm.org/docs/UsersManual.html",
|
||||
"language": "en-US",
|
||||
"name": "clang",
|
||||
"rules": [
|
||||
{
|
||||
"defaultConfiguration": {
|
||||
"enabled": true,
|
||||
"level": "warning",
|
||||
"rank": -1
|
||||
},
|
||||
"fullDescription": {
|
||||
"text": "Check for dereferences of null pointers"
|
||||
},
|
||||
"helpUri": "https://clang.llvm.org/docs/analyzer/checkers.html#core-nulldereference",
|
||||
"id": "core.NullDereference",
|
||||
"name": "core.NullDereference"
|
||||
}
|
||||
],
|
||||
"version": "[clang version]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": "[SARIF version]"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// RUN: rm -rf %t && mkdir %t
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -verify -analyzer-output=sarif-html -o %t%{fs-sep}out1.sarif
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -verify -analyzer-output=sarif-html -o %t%{fs-sep}out2.sarif
|
||||
// RUN: cat %t%{fs-sep}out1.sarif | %normalize_sarif | diff -U1 -b %S/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif -
|
||||
// RUN: cat %t%{fs-sep}out2.sarif | %normalize_sarif | diff -U1 -b %S/Inputs/expected-sarif/sarif-multi-file-diagnostics.c.sarif -
|
||||
|
||||
int test(int *p) {
|
||||
if (p)
|
||||
return 0;
|
||||
else
|
||||
return *p; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
|
||||
}
|
||||
@@ -21,11 +21,15 @@ config.substitutions.append(
|
||||
config.substitutions.append(
|
||||
(
|
||||
"%normalize_sarif",
|
||||
"grep -Ev '^[[:space:]]*(%s|%s|%s)[[:space:]]*$'"
|
||||
"sed -r '%s;%s;%s;%s'"
|
||||
% (
|
||||
'"uri": "file:.*%basename_t"',
|
||||
'"version": ".* version .*"',
|
||||
'"version": "2.1.0"',
|
||||
# Replace version strings that are likely to change.
|
||||
r's/"version": ".* version .*"/"version": "[clang version]"/',
|
||||
r's/"version": "2.1.0"/"version": "[SARIF version]"/',
|
||||
# Strip directories from file URIs
|
||||
r's/"file:(\/+)([^"\/]+\/)*([^"]+)"/"file:\1[...]\/\3"/',
|
||||
# Set "length" to -1
|
||||
r's/"length": [[:digit:]]+/"length": -1/'
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user