]> granicus.if.org Git - clang/commitdiff
More accurately model realloc() when the size argument is 0. realloc() with a size...
authorLenny Maiorani <lenny@colorado.edu>
Wed, 27 Apr 2011 14:49:29 +0000 (14:49 +0000)
committerLenny Maiorani <lenny@colorado.edu>
Wed, 27 Apr 2011 14:49:29 +0000 (14:49 +0000)
Unit tests f2_realloc_0(), f6_realloc(), and f7_realloc() contributed by Marshall Clow <mclow.lists@gmail.com>. Thanks!

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

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

index a7655c4fb9d9d710a280a331726cd632be7ec492..91002158c57f772942405dc46c2a7bb89bb24f93 100644 (file)
@@ -501,8 +501,24 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
   DefinedOrUnknownSVal PtrEQ =
     svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
 
-  // If the ptr is NULL, the call is equivalent to malloc(size).
-  if (const GRState *stateEqual = state->assume(PtrEQ, true)) {
+  // Get the size argument. If there is no size arg then give up.
+  const Expr *Arg1 = CE->getArg(1);
+  if (!Arg1)
+    return;
+
+  // Get the value of the size argument.
+  DefinedOrUnknownSVal Arg1Val = 
+    cast<DefinedOrUnknownSVal>(state->getSVal(Arg1));
+
+  // Compare the size argument to 0.
+  DefinedOrUnknownSVal SizeZero =
+    svalBuilder.evalEQ(state, Arg1Val,
+                       svalBuilder.makeIntValWithPtrWidth(0, false));
+
+  // If the ptr is NULL and the size is not 0, the call is equivalent to 
+  // malloc(size).
+  const GRState *stateEqual = state->assume(PtrEQ, true);
+  if (stateEqual && state->assume(SizeZero, false)) {
     // Hack: set the NULL symbolic region to released to suppress false warning.
     // In the future we should add more states for allocated regions, e.g., 
     // CheckedNull, CheckedNonNull.
@@ -517,17 +533,17 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
   }
 
   if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
-    const Expr *Arg1 = CE->getArg(1);
-    DefinedOrUnknownSVal Arg1Val = 
-      cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
-    DefinedOrUnknownSVal SizeZero =
-      svalBuilder.evalEQ(stateNotEqual, Arg1Val,
-                         svalBuilder.makeIntValWithPtrWidth(0, false));
-
+    // If the size is 0, free the memory.
     if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
-      if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false))
-        C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+      if (const GRState *stateFree = 
+          FreeMemAux(C, CE, stateSizeZero, 0, false)) {
+
+        // Add the state transition to set input pointer argument to be free.
+        C.addTransition(stateFree);
 
+        // Bind the return value to UndefinedVal because it is now free.
+        C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+      }
     if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
       if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
                                                 0, false)) {
index c13e15257be0137a3c6be5b5463a26cb3df9876b..f9af199b5fad44c05063d7f5fcd894b1d752d182 100644 (file)
@@ -33,6 +33,17 @@ void f2() {
   free(p); // expected-warning{{Try to free a memory block that has been released}}
 }
 
+void f2_realloc_0() {
+  int *p = malloc(12);
+  realloc(p,0);
+  realloc(p,0); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+void f2_realloc_1() {
+  int *p = malloc(12);
+  int *q = realloc(p,0); // expected-warning{{Assigned value is garbage or undefined}}
+}
+
 // ownership attributes tests
 void naf1() {
   int *p = my_malloc3(12);
@@ -166,6 +177,15 @@ void f6() {
     free(p);
 }
 
+void f6_realloc() {
+  int *p = malloc(12);
+  if (!p)
+    return; // no-warning
+  else
+    realloc(p,0);
+}
+
+
 char *doit2();
 void pr6069() {
   char *buf = doit2();
@@ -182,6 +202,12 @@ void f7() {
   x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
 }
 
+void f7_realloc() {
+  char *x = (char*) malloc(4);
+  realloc(x,0);
+  x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+}
+
 void PR6123() {
   int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
 }