Index: lib/StaticAnalyzer/Core/SarifDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -232,6 +232,43 @@ {"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 @@ }); return json::Object{{"tool", createTool()}, + {"resources", createResources(Diags)}, {"results", std::move(Results)}, {"files", std::move(Files)}}; } Index: test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif =================================================================== --- test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif +++ 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": [ Index: test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif =================================================================== --- test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif +++ 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" +} Index: test/Analysis/diagnostics/sarif-diagnostics-taint-test.c =================================================================== --- test/Analysis/diagnostics/sarif-diagnostics-taint-test.c +++ 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); Index: test/Analysis/diagnostics/sarif-multi-diagnostic-test.c =================================================================== --- test/Analysis/diagnostics/sarif-multi-diagnostic-test.c +++ 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; +} + Index: test/Analysis/lit.local.cfg =================================================================== --- test/Analysis/lit.local.cfg +++ test/Analysis/lit.local.cfg @@ -14,5 +14,9 @@ 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