]> granicus.if.org Git - clang/commitdiff
[analyzer] Malloc Checker: realloc: add dependency between the symbols
authorAnna Zaks <ganna@apple.com>
Tue, 14 Feb 2012 00:26:13 +0000 (00:26 +0000)
committerAnna Zaks <ganna@apple.com>
Tue, 14 Feb 2012 00:26:13 +0000 (00:26 +0000)
in realloc map.

If there is no dependency, the reallocated ptr will get garbage
collected before we know that realloc failed, which would lead us to
missing a memory leak warning.

Also added new test cases, which we can handle now.
Plus minor cleanups.

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

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

index 9329d5251f16a4546d3468d5b8275358858aa71a..7cbb49e2d8f0b0e009e1a39d55d61317d31a6645 100644 (file)
@@ -409,17 +409,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
   if (!isa<Loc>(location))
     return 0;
 
-  // FIXME: Technically using 'Assume' here can result in a path
-  //  bifurcation.  In such cases we need to return two states, not just one.
+  // The explicit NULL case, no operation is performed.
   ProgramStateRef notNullState, nullState;
   llvm::tie(notNullState, nullState) = state->assume(location);
-
-  // The explicit NULL case, no operation is performed.
   if (nullState && !notNullState)
     return 0;
 
-  assert(notNullState);
-
   // Unknown values could easily be okay
   // Undefined values are handled elsewhere
   if (ArgVal.isUnknownOrUndef())
@@ -490,8 +485,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
 
   // Normal free.
   if (Hold)
-    return notNullState->set<RegionState>(Sym, RefState::getRelinquished(CE));
-  return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
+    return state->set<RegionState>(Sym, RefState::getRelinquished(CE));
+  return state->set<RegionState>(Sym, RefState::getReleased(CE));
 }
 
 bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -685,6 +680,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
       // If size was equal to 0, either NULL or a pointer suitable to be passed
       // to free() is returned.
       stateFree = stateFree->set<ReallocPairs>(ToPtr, FromPtr);
+      C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
       C.addTransition(stateFree);
       return;
     }
@@ -697,6 +693,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
     if (!stateRealloc)
       return;
     stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr);
+    C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
     C.addTransition(stateRealloc);
     return;
   }
@@ -918,7 +915,7 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
         if (RS->isReleased())
           state = state->set<RegionState>(I.getData(),
                              RefState::getAllocateUnchecked(RS->getStmt()));
-        if (RS->isAllocated())
+        else if (RS->isAllocated())
           state = state->set<RegionState>(I.getData(),
                              RefState::getReleased(RS->getStmt()));
       }
index b819caa0ac9e0655ca4b377f799d5d2d7b3aae09..0aa9291255998e6c34a94446d83574be49993640 100644 (file)
@@ -109,6 +109,47 @@ void reallocPtrZero3() {
   free(r);
 }
 
+void reallocRadar6337483_1() {
+    char *buf = malloc(100);
+    buf = (char*)realloc(buf, 0x1000000);
+    if (!buf) {
+        return;// expected-warning {{Allocated memory never released.}}
+    }
+    free(buf);
+}
+
+void reallocRadar6337483_2() {
+    char *buf = malloc(100);
+    char *buf2 = (char*)realloc(buf, 0x1000000);
+    if (!buf2) { // expected-warning {{Allocated memory never released.}}
+      ;
+    } else {
+      free(buf2);
+    }
+}
+
+void reallocRadar6337483_3() {
+    char * buf = malloc(100);
+    char * tmp;
+    tmp = (char*)realloc(buf, 0x1000000);
+    if (!tmp) {
+        free(buf);
+        return;
+    }
+    buf = tmp;
+    free(buf);
+}
+
+void reallocRadar6337483_4() {
+    char *buf = malloc(100);
+    char *buf2 = (char*)realloc(buf, 0x1000000);
+    if (!buf2) {
+      return;  // expected-warning {{Allocated memory never released.}}
+    } else {
+      free(buf2);
+    }
+}
+
 // This case tests that storing malloc'ed memory to a static variable which is
 // then returned is not leaked.  In the absence of known contracts for functions
 // or inter-procedural analysis, this is a conservative answer.