]> granicus.if.org Git - clang/commitdiff
[analyzer] Track malloc'd memory into struct fields.
authorJordan Rose <jordan_rose@apple.com>
Wed, 20 Mar 2013 20:35:57 +0000 (20:35 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 20 Mar 2013 20:35:57 +0000 (20:35 +0000)
Due to improper modelling of copy constructors (specifically, their
const reference arguments), we were producing spurious leak warnings
for allocated memory stored in structs. In order to silence this, we
decided to consider storing into a struct to be the same as escaping.
However, the previous commit has fixed this issue and we can now properly
distinguish leaked memory that happens to be in a struct from a buffer
that escapes within a struct wrapper.

Originally applied in r161511, reverted in r174468.
<rdar://problem/12945937>

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/malloc-annotations.c
test/Analysis/malloc.c
test/Analysis/simple-stream-checks.c

index 53cea0f9a2324be7c644e258f00b6420f725ef1b..b619c5e02482c4c585b90a5f4a5a63a34bea48b3 100644 (file)
@@ -1692,12 +1692,6 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
       if (StoredVal != Val)
         escapes = (State == (State->bindLoc(*regionLoc, Val)));
     }
-    if (!escapes) {
-      // Case 4: We do not currently model what happens when a symbol is
-      // assigned to a struct field, so be conservative here and let the symbol
-      // go. TODO: This could definitely be improved upon.
-      escapes = !isa<VarRegion>(regionLoc->getRegion());
-    }
   }
 
   // If our store can represent the binding and we aren't storing to something
index bdd50c6be5a0a7f9d814ec8ac97d3a93d08a3774..3a260c3aefd4b7229ef79637b877c2787352c826 100644 (file)
@@ -70,6 +70,11 @@ void af1_c() {
   myglobalpointer = my_malloc(12); // no-warning
 }
 
+void af1_d() {
+  struct stuff mystuff;
+  mystuff.somefield = my_malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
+
 // Test that we can pass out allocated memory via pointer-to-pointer.
 void af1_e(void **pp) {
   *pp = my_malloc(42); // no-warning
@@ -262,14 +267,3 @@ void testMultipleFreeAnnotations() {
   my_freeBoth(p, q);
 }
 
-// ----------------------------------------------------------------------------
-
-// False negatives.
-
-// Pending on removal of the escaping on assignment to struct fields.
-void af1_d() {
-  struct stuff mystuff;
-  mystuff.somefield = my_malloc(12);
-} // missing warning
-
-
index e8b4ad3b4df2c1536523c7e09221c8fcaa56f34a..7790b32b078ec6a5210be86182fe41794afc6bf6 100644 (file)
@@ -531,6 +531,12 @@ int *testMalloc3() {
   return y; // no-warning
 }
 
+void testStructLeak() {
+  StructWithPtr St;
+  St.memP = malloc(12);
+  return; // expected-warning {{Memory is never released; potential leak of memory pointed to by 'St.memP'}}
+}
+
 void testElemRegion1() {
   char *x = (void*)malloc(2);
   int *ix = (int*)x;
@@ -929,6 +935,18 @@ int cmpHeapAllocationToUnknown() {
   return 0;
 }
 
+void localArrayTest() {
+  char *p = (char*)malloc(12);
+  char *ArrayL[12];
+  ArrayL[0] = p;
+} // expected-warning {{leak}}
+
+void localStructTest() {
+  StructWithPtr St;
+  StructWithPtr *pSt = &St;
+  pSt->memP = malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
+
 #ifdef __INTPTR_TYPE__
 // Test double assignment through integers.
 typedef __INTPTR_TYPE__ intptr_t;
@@ -1045,50 +1063,18 @@ void testPassToSystemHeaderFunctionIndirectly() {
   fakeSystemHeaderCallInt(p);
 } // expected-warning {{leak}}
 
-// ----------------------------------------------------------------------------
-// False negatives.
-
-// TODO: This is another false negative.
-void testMallocWithParam(int **p) {
-  *p = (int*) malloc(sizeof(int));
-  *p = 0;
-}
-
-void testMallocWithParam_2(int **p) {
-  *p = (int*) malloc(sizeof(int));
-}
-
-// Pending on removal of the escaping on assignment to struct fields.
-void testStructLeak() {
-  StructWithPtr St;
-  St.memP = malloc(12);
-  return; // missing warning
-}
-
-void localArrayTest() {
-  char *p = (char*)malloc(12);
-  char *ArrayL[12];
-  ArrayL[0] = p;
-} // missing warning
-
-void localStructTest() {
-  StructWithPtr St;
-  StructWithPtr *pSt = &St;
-  pSt->memP = malloc(12);
-} // missing warning
-
 void testPassConstPointerIndirectlyStruct() {
   struct HasPtr hp;
   hp.p = malloc(10);
   memcmp(&hp, &hp, sizeof(hp));
-  return; // missing leak
+  return; // expected-warning {{Memory is never released; potential leak of memory pointed to by 'hp.p'}}
 }
 
 void testPassToSystemHeaderFunctionIndirectlyStruct() {
   SomeStruct ss;
   ss.p = malloc(1);
   fakeSystemHeaderCall(&ss);
-} // missing leak
+} // expected-warning {{Memory is never released; potential leak of memory pointed to by 'ss.p'}}
 
 int *testOffsetAllocate(size_t size) {
   int *memoryBlock = (int *)malloc(size + sizeof(int));
@@ -1202,3 +1188,15 @@ void freeMemory() {
     poolFreeC(_vectorSegments[_nVectorSegments++]);
   }
 }
+
+// ----------------------------------------------------------------------------
+// False negatives.
+
+void testMallocWithParam(int **p) {
+  *p = (int*) malloc(sizeof(int));
+  *p = 0; // FIXME: should warn here
+}
+
+void testMallocWithParam_2(int **p) {
+  *p = (int*) malloc(sizeof(int)); // no-warning
+}
index 1fb6de3ec17b5c1c52b3db5c522ee74489363d5f..ce57fa7ac34e6e8db4027bc86687e7266b3713c1 100644 (file)
@@ -88,4 +88,4 @@ void testPassToSystemHeaderFunctionIndirectly() {
   FileStruct fs;
   fs.p = fopen("myfile.txt", "w");
   fakeSystemHeaderCall(&fs);
-} // expected leak warning
+}  // expected-warning {{Opened file is never closed; potential resource leak}}