aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h5
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp25
-rw-r--r--test/Analysis/diagnostics/false-positive-suppression.c23
-rw-r--r--test/Analysis/diagnostics/include/sys/queue.h5
4 files changed, 58 insertions, 0 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 7a87e47f74..74579b7b4c 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -457,6 +457,11 @@ public:
void Register(BugType *BT);
+ /// \brief Suppress reports that might lead to known false positives.
+ ///
+ /// Currently this suppresses reports based on locations of bugs.
+ bool suppressReport(BugReport *R);
+
/// \brief Add the given report to the set of reports tracked by BugReporter.
///
/// The reports are usually generated by the checkers. Further, they are
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 8e6bc69cc4..d64aa39feb 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2137,7 +2137,32 @@ void BugReporter::Register(BugType *BT) {
BugTypes = F.add(BugTypes, BT);
}
+bool BugReporter::suppressReport(BugReport *R) {
+ const Stmt *S = R->getStmt();
+ if (!S)
+ return false;
+
+ // Here we suppress false positives coming from system macros. This list is
+ // based on known issues.
+
+ // Skip reports within the sys/queue.h macros as we do not have the ability to
+ // reason about data structure shapes.
+ SourceManager &SM = getSourceManager();
+ SourceLocation Loc = S->getLocStart();
+ while (Loc.isMacroID()) {
+ if (SM.isInSystemMacro(Loc) &&
+ (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h")))
+ return true;
+ Loc = SM.getSpellingLoc(Loc);
+ }
+
+ return false;
+}
+
void BugReporter::emitReport(BugReport* R) {
+ if (suppressReport(R))
+ return;
+
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
diff --git a/test/Analysis/diagnostics/false-positive-suppression.c b/test/Analysis/diagnostics/false-positive-suppression.c
new file mode 100644
index 0000000000..420a573380
--- /dev/null
+++ b/test/Analysis/diagnostics/false-positive-suppression.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// expected-no-diagnostics
+
+#include "include/sys/queue.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+int radar12491259() {
+ int *p = malloc(12);
+ FREE_POINTER(p);
+ FREE_POINTER(p); // no-warning: we are suppressing errors coming from sys/queue macros.
+ return 0;
+}
+
+#define MYMACRO(p) FREE_POINTER(p)
+
+int radar12491259_inside_macro() {
+ int *p = malloc(12);
+ MYMACRO(p);
+ MYMACRO(p); // no-warning: we are suppressing errors coming from sys/queue macros.
+ return 0;
+}
diff --git a/test/Analysis/diagnostics/include/sys/queue.h b/test/Analysis/diagnostics/include/sys/queue.h
new file mode 100644
index 0000000000..e5698ed443
--- /dev/null
+++ b/test/Analysis/diagnostics/include/sys/queue.h
@@ -0,0 +1,5 @@
+#pragma clang system_header
+
+void free(void *);
+#define FREE_POINTER(x) free(x)
+