r179075 - [analyzer] Keep tracking the pointer after the escape to more aggressively report mismatched deallocator

Anna Zaks ganna at apple.com
Mon Apr 8 17:30:28 PDT 2013


Author: zaks
Date: Mon Apr  8 19:30:28 2013
New Revision: 179075

URL: http://llvm.org/viewvc/llvm-project?rev=179075&view=rev
Log:
[analyzer] Keep tracking the pointer after the escape to more aggressively report mismatched deallocator

Test that the path notes do not change. I don’t think we should print a note on escape.

Also, I’ve removed a check that assumed that the family stored in the RefStete could be
AF_None and added an assert in the constructor.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
    cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp
    cfe/trunk/test/Analysis/malloc.c

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=179075&r1=179074&r2=179075&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Mon Apr  8 19:30:28 2013
@@ -50,7 +50,12 @@ class RefState {
               Released,
               // The responsibility for freeing resources has transfered from
               // this reference. A relinquished symbol should not be freed.
-              Relinquished };
+              Relinquished,
+              // We are no longer guaranteed to have observed all manipulations
+              // of this pointer/memory. For example, it could have been
+              // passed as a parameter to an opaque function.
+              Escaped
+  };
 
   const Stmt *S;
   unsigned K : 2; // Kind enum, but stored as a bitfield.
@@ -58,12 +63,15 @@ class RefState {
                         // family.
 
   RefState(Kind k, const Stmt *s, unsigned family) 
-    : S(s), K(k), Family(family) {}
+    : S(s), K(k), Family(family) {
+    assert(family != AF_None);
+  }
 public:
   bool isAllocated() const { return K == Allocated; }
   bool isReleased() const { return K == Released; }
   bool isRelinquished() const { return K == Relinquished; }
-  AllocationFamily getAllocationFamily() const { 
+  bool isEscaped() const { return K == Escaped; }
+  AllocationFamily getAllocationFamily() const {
     return (AllocationFamily)Family;
   }
   const Stmt *getStmt() const { return S; }
@@ -81,6 +89,9 @@ public:
   static RefState getRelinquished(unsigned family, const Stmt *s) {
     return RefState(Relinquished, s, family);
   }
+  static RefState getEscaped(const RefState *RS) {
+    return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
+  }
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(K);
@@ -1008,37 +1019,37 @@ ProgramStateRef MallocChecker::FreeMemAu
 
   if (RsBase) {
 
-    bool DeallocMatchesAlloc = 
-      RsBase->getAllocationFamily() == AF_None ||
-      RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
-
-    // Check if an expected deallocation function matches the real one.
-    if (!DeallocMatchesAlloc && RsBase->isAllocated()) {
-      ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase,
-                              SymBase);
-      return 0;
-    }
-
-    // Check double free.
-    if (DeallocMatchesAlloc &&
-        (RsBase->isReleased() || RsBase->isRelinquished()) &&
+    // Check for double free first.
+    if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
         !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
       ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
                        SymBase, PreviousRetStatusSymbol);
       return 0;
-    }
 
-    // Check if the memory location being freed is the actual location
-    // allocated, or an offset.
-    RegionOffset Offset = R->getAsOffset();
-    if (RsBase->isAllocated() &&
-        Offset.isValid() &&
-        !Offset.hasSymbolicOffset() &&
-        Offset.getOffset() != 0) {
-      const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
-      ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 
-                       AllocExpr);
-      return 0;
+    // If the pointer is allocated or escaped, but we are now trying to free it,
+    // check that the call to free is proper.
+    } else if (RsBase->isAllocated() || RsBase->isEscaped()) {
+
+      // Check if an expected deallocation function matches the real one.
+      bool DeallocMatchesAlloc =
+        RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
+      if (!DeallocMatchesAlloc) {
+        ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
+                                ParentExpr, RsBase, SymBase);
+        return 0;
+      }
+
+      // Check if the memory location being freed is the actual location
+      // allocated, or an offset.
+      RegionOffset Offset = R->getAsOffset();
+      if (Offset.isValid() &&
+          !Offset.hasSymbolicOffset() &&
+          Offset.getOffset() != 0) {
+        const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
+        ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 
+                         AllocExpr);
+        return 0;
+      }
     }
   }
 
@@ -1992,8 +2003,10 @@ ProgramStateRef MallocChecker::checkPoin
     SymbolRef sym = *I;
 
     if (const RefState *RS = State->get<RegionState>(sym)) {
-      if (RS->isAllocated() && CheckRefState(RS))
+      if (RS->isAllocated() && CheckRefState(RS)) {
         State = State->remove<RegionState>(sym);
+        State = State->set<RegionState>(sym, RefState::getEscaped(RS));
+      }
     }
   }
   return State;

Modified: cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator%2BNewDelete.cpp?rev=179075&r1=179074&r2=179075&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp (original)
+++ cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp Mon Apr  8 19:30:28 2013
@@ -73,3 +73,35 @@ void testNewOffsetFree() {
   int *p = new int;
   operator delete(++p); // expected-warning{{Argument to operator delete is offset by 4 bytes from the start of memory allocated by 'new'}}
 }
+
+//----------------------------------------------------------------
+// Test that we check for free errors on escaped pointers.
+//----------------------------------------------------------------
+void changePtr(int **p);
+static int *globalPtr;
+void changePointee(int *p);
+
+void testMismatchedChangePtrThroughCall() {
+  int *p = (int*)malloc(sizeof(int)*4);
+  changePtr(&p);
+  delete p; // no-warning the value of the pointer might have changed
+}
+
+void testMismatchedChangePointeeThroughCall() {
+  int *p = (int*)malloc(sizeof(int)*4);
+  changePointee(p);
+  delete p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testShouldReportDoubleFreeNotMismatched() {
+  int *p = (int*)malloc(sizeof(int)*4);
+  globalPtr = p;
+  free(p);
+  delete globalPtr; // expected-warning {{Attempt to free released memory}}
+}
+
+void testMismatchedChangePointeeThroughAssignment() {
+  int *arr = new int[4];
+  globalPtr = arr;
+  delete arr; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
+}
\ No newline at end of file

Modified: cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp?rev=179075&r1=179074&r2=179075&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp (original)
+++ cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp Mon Apr  8 19:30:28 2013
@@ -2,156 +2,158 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=plist %s -o %t.plist
 // RUN: FileCheck --input-file=%t.plist %s
 
+void changePointee(int *p);
 void test() {
   int *p = new int[1];
   // expected-note at -1 {{Memory is allocated}}
+  changePointee(p);
   delete p; // expected-warning {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
   // expected-note at -1 {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
 }
 
-// CHECK:     <key>diagnostics</key>
-// CHECK-NEXT:<array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT:  <key>path</key>
-// CHECK-NEXT:  <array>
-// CHECK-NEXT:   <dict>
-// CHECK-NEXT:    <key>kind</key><string>control</string>
-// CHECK-NEXT:    <key>edges</key>
-// CHECK-NEXT:     <array>
-// CHECK-NEXT:      <dict>
-// CHECK-NEXT:       <key>start</key>
-// CHECK-NEXT:        <array>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>3</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>5</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:        </array>
-// CHECK-NEXT:       <key>end</key>
-// CHECK-NEXT:        <array>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>12</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>14</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:        </array>
-// CHECK-NEXT:      </dict>
-// CHECK-NEXT:     </array>
-// CHECK-NEXT:   </dict>
-// CHECK-NEXT:   <dict>
-// CHECK-NEXT:    <key>kind</key><string>event</string>
-// CHECK-NEXT:    <key>location</key>
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT:  <dict>
+// CHECK-NEXT:   <key>path</key>
+// CHECK-NEXT:   <array>
 // CHECK-NEXT:    <dict>
-// CHECK-NEXT:     <key>line</key><integer>6</integer>
-// CHECK-NEXT:     <key>col</key><integer>12</integer>
-// CHECK-NEXT:     <key>file</key><integer>0</integer>
-// CHECK-NEXT:    </dict>
-// CHECK-NEXT:    <key>ranges</key>
-// CHECK-NEXT:    <array>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
 // CHECK-NEXT:      <array>
 // CHECK-NEXT:       <dict>
-// CHECK-NEXT:        <key>line</key><integer>6</integer>
-// CHECK-NEXT:        <key>col</key><integer>12</integer>
-// CHECK-NEXT:        <key>file</key><integer>0</integer>
-// CHECK-NEXT:       </dict>
-// CHECK-NEXT:       <dict>
-// CHECK-NEXT:        <key>line</key><integer>6</integer>
-// CHECK-NEXT:        <key>col</key><integer>21</integer>
-// CHECK-NEXT:        <key>file</key><integer>0</integer>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>5</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>12</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>14</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
 // CHECK-NEXT:       </dict>
 // CHECK-NEXT:      </array>
-// CHECK-NEXT:    </array>
-// CHECK-NEXT:    <key>depth</key><integer>0</integer>
-// CHECK-NEXT:    <key>extended_message</key>
-// CHECK-NEXT:    <string>Memory is allocated</string>
-// CHECK-NEXT:    <key>message</key>
-// CHECK-NEXT:    <string>Memory is allocated</string>
-// CHECK-NEXT:   </dict>
-// CHECK-NEXT:   <dict>
-// CHECK-NEXT:    <key>kind</key><string>control</string>
-// CHECK-NEXT:    <key>edges</key>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>7</integer>
+// CHECK-NEXT:      <key>col</key><integer>12</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
 // CHECK-NEXT:     <array>
-// CHECK-NEXT:      <dict>
-// CHECK-NEXT:       <key>start</key>
-// CHECK-NEXT:        <array>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>12</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>6</integer>
-// CHECK-NEXT:          <key>col</key><integer>14</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:        </array>
-// CHECK-NEXT:       <key>end</key>
-// CHECK-NEXT:        <array>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>8</integer>
-// CHECK-NEXT:          <key>col</key><integer>3</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:         <dict>
-// CHECK-NEXT:          <key>line</key><integer>8</integer>
-// CHECK-NEXT:          <key>col</key><integer>8</integer>
-// CHECK-NEXT:          <key>file</key><integer>0</integer>
-// CHECK-NEXT:         </dict>
-// CHECK-NEXT:        </array>
-// CHECK-NEXT:      </dict>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>7</integer>
+// CHECK-NEXT:         <key>col</key><integer>12</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>7</integer>
+// CHECK-NEXT:         <key>col</key><integer>21</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
 // CHECK-NEXT:     </array>
-// CHECK-NEXT:   </dict>
-// CHECK-NEXT:   <dict>
-// CHECK-NEXT:    <key>kind</key><string>event</string>
-// CHECK-NEXT:    <key>location</key>
-// CHECK-NEXT:    <dict>
-// CHECK-NEXT:     <key>line</key><integer>8</integer>
-// CHECK-NEXT:     <key>col</key><integer>3</integer>
-// CHECK-NEXT:     <key>file</key><integer>0</integer>
+// CHECK-NEXT:     <key>depth</key><integer>0</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Memory is allocated</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Memory is allocated</string>
 // CHECK-NEXT:    </dict>
-// CHECK-NEXT:    <key>ranges</key>
-// CHECK-NEXT:    <array>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
 // CHECK-NEXT:      <array>
 // CHECK-NEXT:       <dict>
-// CHECK-NEXT:        <key>line</key><integer>8</integer>
-// CHECK-NEXT:        <key>col</key><integer>10</integer>
-// CHECK-NEXT:        <key>file</key><integer>0</integer>
-// CHECK-NEXT:       </dict>
-// CHECK-NEXT:       <dict>
-// CHECK-NEXT:        <key>line</key><integer>8</integer>
-// CHECK-NEXT:        <key>col</key><integer>10</integer>
-// CHECK-NEXT:        <key>file</key><integer>0</integer>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>12</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>14</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>col</key><integer>8</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
 // CHECK-NEXT:       </dict>
 // CHECK-NEXT:      </array>
-// CHECK-NEXT:    </array>
-// CHECK-NEXT:    <key>depth</key><integer>0</integer>
-// CHECK-NEXT:    <key>extended_message</key>
-// CHECK-NEXT:    <string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
-// CHECK-NEXT:    <key>message</key>
-// CHECK-NEXT:    <string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
-// CHECK-NEXT:   </dict>
-// CHECK-NEXT:  </array>
-// CHECK-NEXT:  <key>description</key><string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
-// CHECK-NEXT:  <key>category</key><string>Memory Error</string>
-// CHECK-NEXT:  <key>type</key><string>Bad deallocator</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>test</string>
-// CHECK-NEXT: <key>issue_hash</key><string>3</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT:  <key>line</key><integer>8</integer>
-// CHECK-NEXT:  <key>col</key><integer>3</integer>
-// CHECK-NEXT:  <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT:</array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>10</integer>
+// CHECK-NEXT:      <key>col</key><integer>3</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
+// CHECK-NEXT:     <array>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>col</key><integer>10</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>col</key><integer>10</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </array>
+// CHECK-NEXT:     <key>depth</key><integer>0</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:   </array>
+// CHECK-NEXT:   <key>description</key><string>Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'</string>
+// CHECK-NEXT:   <key>category</key><string>Memory Error</string>
+// CHECK-NEXT:   <key>type</key><string>Bad deallocator</string>
+// CHECK-NEXT:  <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT:  <key>issue_context</key><string>test</string>
+// CHECK-NEXT:  <key>issue_hash</key><string>4</string>
+// CHECK-NEXT:  <key>location</key>
+// CHECK-NEXT:  <dict>
+// CHECK-NEXT:   <key>line</key><integer>10</integer>
+// CHECK-NEXT:   <key>col</key><integer>3</integer>
+// CHECK-NEXT:   <key>file</key><integer>0</integer>
+// CHECK-NEXT:  </dict>
+// CHECK-NEXT:  </dict>
+// CHECK-NEXT: </array>

Modified: cfe/trunk/test/Analysis/malloc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/malloc.c?rev=179075&r1=179074&r2=179075&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/malloc.c (original)
+++ cfe/trunk/test/Analysis/malloc.c Mon Apr  8 19:30:28 2013
@@ -1107,7 +1107,7 @@ void testOffsetOfRegionFreedAfterFunctio
   int *p = malloc(sizeof(int)*2);
   p += 1;
   myfoo(p);
-  free(p); // no-warning
+  free(p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
 }
 
 void testFixManipulatedPointerBeforeFree() {





More information about the cfe-commits mailing list