r259222 - [analyzer] Suppress null reports from defensive checks in function-like macros.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 29 10:47:13 PST 2016


Author: dcoughlin
Date: Fri Jan 29 12:47:13 2016
New Revision: 259222

URL: http://llvm.org/viewvc/llvm-project?rev=259222&view=rev
Log:
[analyzer] Suppress null reports from defensive checks in function-like macros.

We already do this for case splits introduced as a result of defensive null
checks in functions and methods, so do the same for function-like macros.

rdar://problem/19640441

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
    cfe/trunk/test/Analysis/inlining/false-positive-suppression.c

Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=259222&r1=259221&r2=259222&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Fri Jan 29 12:47:13 2016
@@ -828,8 +828,33 @@ SuppressInlineDefensiveChecksVisitor::Vi
     // Check if this is inlined defensive checks.
     const LocationContext *CurLC =Succ->getLocationContext();
     const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
-    if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+    if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
       BR.markInvalid("Suppress IDC", CurLC);
+      return nullptr;
+    }
+
+    // Treat defensive checks in function-like macros as if they were an inlined
+    // defensive check.
+    auto CurPoint = Succ->getLocation().getAs<BlockEdge>();
+    auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
+
+    if (!CurPoint || !BugPoint)
+      return nullptr;
+
+    SourceLocation CurLoc =
+        CurPoint->getSrc()->getTerminator().getStmt()->getLocStart();
+    SourceLocation BugLoc = BugPoint->getStmt()->getLocStart();
+
+    if (CurLoc.isMacroID() && !BugLoc.isMacroID()) {
+      const SourceManager &SMgr = BRC.getSourceManager();
+      std::pair<FileID, unsigned> CLInfo = SMgr.getDecomposedLoc(CurLoc);
+      SrcMgr::SLocEntry SE = SMgr.getSLocEntry(CLInfo.first);
+      const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion();
+      if (EInfo.isFunctionMacroExpansion()) {
+        BR.markInvalid("Suppress Macro IDC", CurLC);
+        return nullptr;
+      }
+    }
   }
   return nullptr;
 }

Modified: cfe/trunk/test/Analysis/inlining/false-positive-suppression.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/false-positive-suppression.c?rev=259222&r1=259221&r2=259222&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/inlining/false-positive-suppression.c (original)
+++ cfe/trunk/test/Analysis/inlining/false-positive-suppression.c Fri Jan 29 12:47:13 2016
@@ -93,6 +93,74 @@ int triggerDivZero () {
   return 5/y; // expected-warning {{Division by zero}}
 }
 
+// Treat a function-like macro similarly to an inlined function, so suppress
+// warnings along paths resulting from inlined checks.
+#define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17)
+void testInlineCheckInMacro(int *p) {
+  int i = MACRO_WITH_CHECK(p);
+  (void)i;
+
+  *p = 1; // no-warning
+}
+
+#define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } )
+void testInlineCheckInNestedMacro(int *p) {
+  int i = MACRO_WITH_NESTED_CHECK(p);
+  (void)i;
+
+  *p = 1; // no-warning
+}
+
+// If there is a check in a macro that is not function-like, don't treat
+// it like a function so don't suppress.
+#define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17)
+void testNonFunctionMacro(int *p) {
+  int i = NON_FUNCTION_MACRO_WITH_CHECK ;
+  (void)i;
+
+  *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+
+// This macro will dereference its argument if the argument is NULL.
+#define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a)
+void testErrorInMacro(int *p) {
+  int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+  (void)i;
+}
+
+// Here the check (the "if") is not in a macro, so we should still warn.
+#define MACRO_IN_GUARD(a) (!(a))
+void testMacroUsedAsGuard(int *p) {
+  if (MACRO_IN_GUARD(p))
+    *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+// When a nil case split is introduced in a macro and the macro is in a guard,
+// we still shouldn't warn.
+int isNull(int *p);
+int isEqual(int *p, int *q);
+#define ISNULL(ptr)    ((ptr) == 0 || isNull(ptr))
+#define ISEQUAL(a, b)    ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b))
+#define ISNOTEQUAL(a, b)   (!ISEQUAL(a, b))
+void testNestedDisjunctiveMacro(int *p, int *q) {
+  if (ISNOTEQUAL(p,q)) {
+    (void)*p; // no-warning
+    (void)*q; // no-warning
+  }
+
+  (void)*p; // no-warning
+  (void)*q; // no-warning
+}
+
+// Here the check is entirely in non-macro code even though the code itself
+// is a macro argument.
+#define MACRO_DO_IT(a) (a)
+void testErrorInArgument(int *p) {
+  int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c
+  (void)i;
+}
+
 // --------------------------
 // "Suppression suppression"
 // --------------------------




More information about the cfe-commits mailing list