]> granicus.if.org Git - clang/commitdiff
[analyzer] Malloc: track non-allocated but freed memory
authorAnna Zaks <ganna@apple.com>
Fri, 3 Aug 2012 18:30:18 +0000 (18:30 +0000)
committerAnna Zaks <ganna@apple.com>
Fri, 3 Aug 2012 18:30:18 +0000 (18:30 +0000)
There is no reason why we should not track the memory which was not
allocated in the current function, but was freed there. This would
allow to catch more use-after-free and double free with no/limited IPA.

Also fix a realloc issue which surfaced as the result of this patch.

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

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

index 5db85ecb401771ccfb3c6854a7cd77c618f9612f..0a36071cf7c35483473a95da0aa96fc85f66d636 100644 (file)
@@ -679,14 +679,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
   SymbolRef Sym = SR->getSymbol();
   const RefState *RS = state->get<RegionState>(Sym);
 
-  // If the symbol has not been tracked, return. This is possible when free() is
-  // called on a pointer that does not get its pointee directly from malloc(). 
-  // Full support of this requires inter-procedural analysis.
-  if (!RS)
-    return 0;
-
   // Check double free.
-  if (RS->isReleased() || RS->isRelinquished()) {
+  if (RS && (RS->isReleased() || RS->isRelinquished())) {
     if (ExplodedNode *N = C.generateSink()) {
       if (!BT_DoubleFree)
         BT_DoubleFree.reset(
@@ -902,10 +896,8 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
     if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
       // 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.
-      stateFree = stateFree->set<ReallocPairs>(ToPtr,
-                                            ReallocPair(FromPtr, FreesOnFail));
-      C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
+      // to free() is returned. We just free the input pointer and do not add
+      // any constrains on the output pointer.
       return stateFree;
     }
 
@@ -1518,7 +1510,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
 
   const RefState *RS = state->get<RegionState>(Sym);
   const RefState *RSPrev = statePrev->get<RegionState>(Sym);
-  if (!RS && !RSPrev)
+  if (!RS)
     return 0;
 
   const Stmt *S = 0;
index 377642cc58c378a6edc039f49318e4657a9e8384..964424647f6ff4b3ec240b9d4875f197aa527a72 100644 (file)
@@ -69,7 +69,7 @@ void reallocSizeZero1() {
   char *p = malloc(12);
   char *r = realloc(p, 0);
   if (!r) {
-    free(p);
+    free(p); // expected-warning {{Attempt to free released memory}}
   } else {
     free(r);
   }
@@ -79,7 +79,7 @@ void reallocSizeZero2() {
   char *p = malloc(12);
   char *r = realloc(p, 0);
   if (!r) {
-    free(p);
+    free(p); // expected-warning {{Attempt to free released memory}}
   } else {
     free(r);
   }
@@ -321,7 +321,7 @@ void nullFree() {
 void paramFree(int *p) {
   myfoo(p);
   free(p); // no warning
-  myfoo(p); // TODO: This should be a warning.
+  myfoo(p); // expected-warning {{Use of memory after it is freed}}
 }
 
 int* mallocEscapeRet() {
@@ -999,3 +999,11 @@ void foo (xpc_connection_t peer) {
   xpc_connection_resume(peer);
 }
 
+// Make sure we catch errors when we free in a function which does not allocate memory.
+void freeButNoMalloc(int *p, int x){
+  if (x) {
+    free(p);
+    //user forgot a return here.
+  }
+  free(p); // expected-warning {{Attempt to free released memory}}
+}