]> granicus.if.org Git - clang/commitdiff
Output "rule" information in SARIF exports.
authorAaron Ballman <aaron@aaronballman.com>
Thu, 1 Nov 2018 18:57:38 +0000 (18:57 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Thu, 1 Nov 2018 18:57:38 +0000 (18:57 +0000)
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

lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
test/Analysis/diagnostics/Inputs/expected-sarif/sarif-diagnostics-taint-test.c.sarif
test/Analysis/diagnostics/Inputs/expected-sarif/sarif-multi-diagnostic-test.c.sarif [new file with mode: 0644]
test/Analysis/diagnostics/sarif-diagnostics-taint-test.c
test/Analysis/diagnostics/sarif-multi-diagnostic-test.c [new file with mode: 0644]
test/Analysis/lit.local.cfg

index 34e948634a07aacabb560e8be4f7206889eb151b..db1550c63fdc99d51acb6c1cf5e7dc6dfe1ce0ed 100644 (file)
@@ -232,6 +232,43 @@ static json::Object createResult(const PathDiagnostic &Diag,
       {"ruleId", Diag.getCheckName()}};
 }
 
+static StringRef getRuleDescription(StringRef CheckName) {
+  return llvm::StringSwitch<StringRef>(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<const PathDiagnostic *> &Diags) {
+  json::Object Rules;
+  llvm::StringSet<> Seen;
+
+  llvm::for_each(Diags, [&](const PathDiagnostic *D) {
+    StringRef RuleID = D->getCheckName();
+    std::pair<llvm::StringSet<>::iterator, bool> P = Seen.insert(RuleID);
+    if (P.second)
+      Rules[RuleID] = createRule(*D);
+  });
+
+  return Rules;
+}
+
+static json::Object
+createResources(std::vector<const PathDiagnostic *> &Diags) {
+  return json::Object{{"rules", createRules(Diags)}};
+}
+
 static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) {
   json::Array Results;
   json::Object Files;
@@ -241,6 +278,7 @@ static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) {
   });
 
   return json::Object{{"tool", createTool()},
+                      {"resources", createResources(Diags)},
                       {"results", std::move(Results)},
                       {"files", std::move(Files)}};
 }
index 7a6068bd8ce6247b73e36db440deb74bf0045839..d6c77479741ce9da0ed5dc6b64e2e85d44595587 100644 (file)
@@ -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 (file)
index 0000000..ae3c5b1
--- /dev/null
@@ -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 fb025b1b466cd71c6529f4d67b30b326baf5c979..75defbd2fbdf2f34c13313c8d464df6ff84fcdd3 100644 (file)
@@ -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 (file)
index 0000000..481e3a5
--- /dev/null
@@ -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 811af6e54f868b6797b569faca3112657e75ea6f..fdab3cfd12db4425d4706bc02efd87f2555be17c 100644 (file)
@@ -14,5 +14,9 @@ config.test_format = analyzer_test.AnalyzerTest(
 config.substitutions.append(('%diff_plist',
     'diff -u -w -I "<string>/" -I "<string>.:" -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