]> granicus.if.org Git - clang/commitdiff
[analyzer] Malloc checker: Leak bugs should be suppressed by sinks.
authorAnna Zaks <ganna@apple.com>
Sat, 11 Feb 2012 21:02:40 +0000 (21:02 +0000)
committerAnna Zaks <ganna@apple.com>
Sat, 11 Feb 2012 21:02:40 +0000 (21:02 +0000)
Resolves a common false positive, where we were reporting a leak inside
asserts

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150312 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
test/Analysis/malloc.c

index 430a77a5704c9612b73d7651c9232d8657cb1cfa..d858959bd5da48e247cfdf32d2ddba501780bbbb 100644 (file)
@@ -148,6 +148,8 @@ private:
   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
   void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
 
+  void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
+
   /// The bug visitor which allows us to print extra diagnostics along the
   /// BugReport path. For example, showing the allocation site of the leaked
   /// region.
@@ -672,6 +674,25 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
   C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
 }
 
+void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
+                               CheckerContext &C) const {
+  assert(N);
+  if (!BT_Leak) {
+    BT_Leak.reset(new BuiltinBug("Memory leak",
+        "Allocated memory never released. Potential memory leak."));
+    // Leaks should not be reported if they are post-dominated by a sink:
+    // (1) Sinks are higher importance bugs.
+    // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
+    //     with __noreturn functions such as assert() or exit(). We choose not
+    //     to report leaks on such paths.
+    BT_Leak->setSuppressOnSink(true);
+  }
+
+  BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+  R->addVisitor(new MallocBugVisitor(Sym));
+  C.EmitReport(R);
+}
+
 void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                      CheckerContext &C) const
 {
@@ -699,34 +720,23 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
   ExplodedNode *N = C.addTransition(state->set<RegionState>(RS));
 
   if (N && generateReport) {
-    if (!BT_Leak)
-      BT_Leak.reset(new BuiltinBug("Memory leak",
-          "Allocated memory never released. Potential memory leak."));
     for (llvm::SmallVector<SymbolRef, 2>::iterator
-          I = Errors.begin(), E = Errors.end(); I != E; ++I) {
-      BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
-      R->addVisitor(new MallocBugVisitor(*I));
-      C.EmitReport(R);
+         I = Errors.begin(), E = Errors.end(); I != E; ++I) {
+      reportLeak(*I, N, C);
     }
   }
 }
 
-void MallocChecker::checkEndPath(CheckerContext &Ctx) const {
-  ProgramStateRef state = Ctx.getState();
+void MallocChecker::checkEndPath(CheckerContext &C) const {
+  ProgramStateRef state = C.getState();
   RegionStateTy M = state->get<RegionState>();
 
   for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
     RefState RS = I->second;
     if (RS.isAllocated()) {
-      ExplodedNode *N = Ctx.addTransition(state);
-      if (N) {
-        if (!BT_Leak)
-          BT_Leak.reset(new BuiltinBug("Memory leak",
-                    "Allocated memory never released. Potential memory leak."));
-        BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
-        R->addVisitor(new MallocBugVisitor(I->first));
-        Ctx.EmitReport(R);
-      }
+      ExplodedNode *N = C.addTransition(state);
+      if (N)
+        reportLeak(I->first, N, C);
     }
   }
 }
index a219e92787ac4e4d2effcac4cc9de273a1b7d718..89299e6637d55b4b518baf83fcd28a1023b5951a 100644 (file)
@@ -340,21 +340,15 @@ int **RegInvalidationDetect2(int **pp) {
   return 0;// expected-warning {{Allocated memory never released. Potential memory leak.}}
 }
 
-// Below are the known false positives.
-
 extern void exit(int) __attribute__ ((__noreturn__));
 void mallocExit(int *g) {
   struct xx *p = malloc(12);
-
-  if (g != 0) {
-    exit(1); // expected-warning{{Allocated memory never released. Potential memory leak}}
-  }
+  if (g != 0)
+    exit(1);
   free(p);
   return;
 }
 
-
-// TODO: There should be no warning here.
 extern void __assert_fail (__const char *__assertion, __const char *__file,
     unsigned int __line, __const char *__function)
      __attribute__ ((__noreturn__));
@@ -363,11 +357,13 @@ extern void __assert_fail (__const char *__assertion, __const char *__file,
 void mallocAssert(int *g) {
   struct xx *p = malloc(12);
 
-  assert(g != 0); // expected-warning{{Allocated memory never released. Potential memory leak}}
+  assert(g != 0);
   free(p);
   return;
 }
 
+// Below are the known false positives.
+
 // TODO: There should be no warning here.
 void reallocFails(int *g, int f) {
   char *p = malloc(12);