From: Aaron Ballman Date: Thu, 1 Nov 2018 18:57:38 +0000 (+0000) Subject: Output "rule" information in SARIF exports. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=96cb1f83062da466e605acdc276673a5959c1579;p=clang Output "rule" information in SARIF exports. SARIF allows you to export descriptions about rules that are present in the SARIF log. Expose the help text table generated into Checkers.inc as the rule's "full description" and export all of the rules present in the analysis output. This information is useful for analysis result viewers like CodeSonar. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345874 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp index 34e948634a..db1550c63f 100644 --- a/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -232,6 +232,43 @@ static json::Object createResult(const PathDiagnostic &Diag, {"ruleId", Diag.getCheckName()}}; } +static StringRef getRuleDescription(StringRef CheckName) { + return llvm::StringSwitch(CheckName) +#define GET_CHECKERS +#define CHECKER(FULLNAME, CLASS, CXXFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ + .Case(FULLNAME, HELPTEXT) +#include "clang/StaticAnalyzer/Checkers/Checkers.inc" +#undef CHECKER +#undef GET_CHECKERS + ; +} + +static json::Object createRule(const PathDiagnostic &Diag) { + StringRef CheckName = Diag.getCheckName(); + return json::Object{ + {"fullDescription", createMessage(getRuleDescription(CheckName))}, + {"name", createMessage(CheckName)}}; +} + +static json::Object createRules(std::vector &Diags) { + json::Object Rules; + llvm::StringSet<> Seen; + + llvm::for_each(Diags, [&](const PathDiagnostic *D) { + StringRef RuleID = D->getCheckName(); + std::pair::iterator, bool> P = Seen.insert(RuleID); + if (P.second) + Rules[RuleID] = createRule(*D); + }); + + return Rules; +} + +static json::Object +createResources(std::vector &Diags) { + return json::Object{{"rules", createRules(Diags)}}; +} + static json::Object createRun(std::vector &Diags) { json::Array Results; json::Object Files; @@ -241,6 +278,7 @@ static json::Object createRun(std::vector &Diags) { }); return json::Object{{"tool", createTool()}, + {"resources", createResources(Diags)}, {"results", std::move(Results)}, {"files", std::move(Files)}}; } diff --git a/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif b/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif index 7a6068bd8c..d6c7747974 100644 --- a/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif +++ b/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif @@ -7,13 +7,25 @@ "fileLocation": { "uri": "file:sarif-diagnostics-taint-test.c" }, - "length": 510, + "length": 413, "mimeType": "text/plain", "roles": [ "resultFile" ] } }, + "resources": { + "rules": { + "debug.TaintTest": { + "fullDescription": { + "text": "Mark tainted symbols as such." + }, + "name": { + "text": "debug.TaintTest" + } + } + } + }, "results": [ { "codeFlows": [ diff --git a/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif b/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif new file mode 100644 index 0000000000..ae3c5b1fbc --- /dev/null +++ b/test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif @@ -0,0 +1,301 @@ +{ + "$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-10-10", + "runs": [ + { + "files": { + "file:sarif-multi-diagnostic-test.c": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "length": 665, + "mimeType": "text/plain", + "roles": [ + "resultFile" + ] + } + }, + "resources": { + "rules": { + "core.CallAndMessage": { + "fullDescription": { + "text": "Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)" + }, + "name": { + "text": "core.CallAndMessage" + } + }, + "core.DivideZero": { + "fullDescription": { + "text": "Check for division by zero" + }, + "name": { + "text": "core.DivideZero" + } + }, + "debug.TaintTest": { + "fullDescription": { + "text": "Mark tainted symbols as such." + }, + "name": { + "text": "debug.TaintTest" + } + } + } + }, + "results": [ + { + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "importance": "essential", + "location": { + "message": { + "text": "Calling 'f'" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 5, + "endLine": 24, + "startColumn": 3, + "startLine": 24 + } + } + } + }, + { + "importance": "essential", + "location": { + "message": { + "text": "tainted" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 17, + "endLine": 9, + "startColumn": 11, + "startLine": 9 + } + } + } + } + ] + } + ] + } + ], + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 17, + "endLine": 9, + "startColumn": 11, + "startLine": 9 + } + } + } + ], + "message": { + "text": "tainted" + }, + "ruleId": "debug.TaintTest" + }, + { + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "importance": "essential", + "location": { + "message": { + "text": "Calling 'g'" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 5, + "endLine": 25, + "startColumn": 3, + "startLine": 25 + } + } + } + }, + { + "importance": "essential", + "location": { + "message": { + "text": "'fp' declared without an initial value" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 10, + "endLine": 13, + "startColumn": 3, + "startLine": 13 + } + } + } + }, + { + "importance": "essential", + "location": { + "message": { + "text": "Called function pointer is an uninitialized pointer value" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 8, + "endLine": 14, + "startColumn": 3, + "startLine": 14 + } + } + } + } + ] + } + ] + } + ], + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 8, + "endLine": 14, + "startColumn": 3, + "startLine": 14 + } + } + } + ], + "message": { + "text": "Called function pointer is an uninitialized pointer value" + }, + "ruleId": "core.CallAndMessage" + }, + { + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "importance": "important", + "location": { + "message": { + "text": "Assuming 'i' is equal to 0" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 12, + "endLine": 18, + "startColumn": 7, + "startLine": 18 + } + } + } + }, + { + "importance": "unimportant", + "location": { + "message": { + "text": "Taking true branch" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 3, + "endLine": 18, + "startColumn": 3, + "startLine": 18 + } + } + } + }, + { + "importance": "essential", + "location": { + "message": { + "text": "Division by zero" + }, + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 14, + "endLine": 19, + "startColumn": 14, + "startLine": 19 + } + } + } + } + ] + } + ] + } + ], + "locations": [ + { + "physicalLocation": { + "fileLocation": { + "uri": "file:sarif-multi-diagnostic-test.c" + }, + "region": { + "endColumn": 14, + "endLine": 19, + "startColumn": 14, + "startLine": 19 + } + } + } + ], + "message": { + "text": "Division by zero" + }, + "ruleId": "core.DivideZero" + } + ], + "tool": { + "fullName": "clang static analyzer", + "language": "en-US", + "name": "clang", + "version": "clang version 8.0.0 (trunk 345822) (llvm/trunk 345824)" + } + } + ], + "version": "2.0.0-csd.2.beta.2018-10-10" +} diff --git a/test/Analysis/diagnostics/sarif-diagnostics-taint-test.c b/test/Analysis/diagnostics/sarif-diagnostics-taint-test.c index fb025b1b46..75defbd2fb 100644 --- a/test/Analysis/diagnostics/sarif-diagnostics-taint-test.c +++ b/test/Analysis/diagnostics/sarif-diagnostics-taint-test.c @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify -analyzer-output=sarif -o - | diff -U1 -w -I ".*file:.*sarif-diagnostics-taint-test.c" -I '"version":' -I "2\.0\.0\-csd\.[0-9]*\.beta\." - %S/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify -analyzer-output=sarif -o - | %diff_sarif %S/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif #include "../Inputs/system-header-simulator.h" int atoi(const char *nptr); diff --git a/test/Analysis/diagnostics/sarif-multi-diagnostic-test.c b/test/Analysis/diagnostics/sarif-multi-diagnostic-test.c new file mode 100644 index 0000000000..481e3a5814 --- /dev/null +++ b/test/Analysis/diagnostics/sarif-multi-diagnostic-test.c @@ -0,0 +1,29 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.security.taint,debug.TaintTest %s -verify -analyzer-output=sarif -o - | %diff_sarif %S/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif +#include "../Inputs/system-header-simulator.h" + +int atoi(const char *nptr); + +void f(void) { + char s[80]; + scanf("%s", s); + int d = atoi(s); // expected-warning {{tainted}} +} + +void g(void) { + void (*fp)(int); + fp(12); // expected-warning {{Called function pointer is an uninitialized pointer value}} +} + +int h(int i) { + if (i == 0) + return 1 / i; // expected-warning {{Division by zero}} + return 0; +} + +int main(void) { + f(); + g(); + h(0); + return 0; +} + diff --git a/test/Analysis/lit.local.cfg b/test/Analysis/lit.local.cfg index 811af6e54f..fdab3cfd12 100644 --- a/test/Analysis/lit.local.cfg +++ b/test/Analysis/lit.local.cfg @@ -14,5 +14,9 @@ config.test_format = analyzer_test.AnalyzerTest( config.substitutions.append(('%diff_plist', 'diff -u -w -I "/" -I ".:" -I "version" -')) +# Diff command for testing SARIF output to reference output. +config.substitutions.append(('%diff_sarif', + '''diff -U1 -w -I ".*file:.*%basename_t" -I '"version":' -I "2\.0\.0\-csd\.[0-9]*\.beta\." -''')) + if not config.root.clang_staticanalyzer: config.unsupported = True