]> granicus.if.org Git - clang/commitdiff
[analyzer] Malloc Checker: realloc: correct the way we are handing the
authorAnna Zaks <ganna@apple.com>
Mon, 13 Feb 2012 20:57:07 +0000 (20:57 +0000)
committerAnna Zaks <ganna@apple.com>
Mon, 13 Feb 2012 20:57:07 +0000 (20:57 +0000)
case when size is 0.

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

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

index 98298c850bf300e4ee8fa6264d2f17102a303835..9329d5251f16a4546d3468d5b8275358858aa71a 100644 (file)
@@ -670,18 +670,22 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
   if (PrtIsNull && SizeIsZero)
     return;
 
+  // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
   assert(!PrtIsNull);
+  SymbolRef FromPtr = arg0Val.getAsSymbol();
+  SVal RetVal = state->getSVal(CE, LCtx);
+  SymbolRef ToPtr = RetVal.getAsSymbol();
+  if (!FromPtr || !ToPtr)
+    return;
 
   // If the size is 0, free the memory.
   if (SizeIsZero)
     if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
-      // Bind the return value to NULL because it is now free.
-      // TODO: This is tricky. Does not currently work.
       // The semantics of the return value are:
       // If size was equal to 0, either NULL or a pointer suitable to be passed
       // to free() is returned.
-      C.addTransition(stateFree->BindExpr(CE, LCtx,
-          svalBuilder.makeNull(), true));
+      stateFree = stateFree->set<ReallocPairs>(ToPtr, FromPtr);
+      C.addTransition(stateFree);
       return;
     }
 
@@ -690,10 +694,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
     // FIXME: We should copy the content of the original buffer.
     ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
                                                 UnknownVal(), stateFree);
-    SymbolRef FromPtr = arg0Val.getAsSymbol();
-    SVal RetVal = state->getSVal(CE, LCtx);
-    SymbolRef ToPtr = RetVal.getAsSymbol();
-    if (!stateRealloc || !FromPtr || !ToPtr)
+    if (!stateRealloc)
       return;
     stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr);
     C.addTransition(stateRealloc);
index d1d850c6810a0142d9f080f2e85d4e98cf2d2900..b819caa0ac9e0655ca4b377f799d5d2d7b3aae09 100644 (file)
@@ -58,6 +58,57 @@ void reallocFails() {
   }
 }
 
+void reallocSizeZero1() {
+  char *p = malloc(12);
+  char *r = realloc(p, 0);
+  if (!r) {
+    free(p);
+  } else {
+    free(r);
+  }
+}
+
+void reallocSizeZero2() {
+  char *p = malloc(12);
+  char *r = realloc(p, 0);
+  if (!r) {
+    free(p);
+  } else {
+    free(r);
+  }
+  free(p); // expected-warning {{Try to free a memory block that has been released}}
+}
+
+void reallocSizeZero3() {
+  char *p = malloc(12);
+  char *r = realloc(p, 0);
+  free(r);
+}
+
+void reallocSizeZero4() {
+  char *r = realloc(0, 0);
+  free(r);
+}
+
+void reallocSizeZero5() {
+  char *r = realloc(0, 0);
+}
+
+void reallocPtrZero1() {
+  char *r = realloc(0, 12); // expected-warning {{Allocated memory never released.}}
+}
+
+void reallocPtrZero2() {
+  char *r = realloc(0, 12);
+  if (r)
+    free(r);
+}
+
+void reallocPtrZero3() {
+  char *r = realloc(0, 12);
+  free(r);
+}
+
 // 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.