r178814 - [analyzer] Reduced the unwanted correlations between checkers living inside MallocChecker.cpp

Anton Yartsev anton.yartsev at gmail.com
Thu Apr 4 16:46:29 PDT 2013


Author: ayartsev
Date: Thu Apr  4 18:46:29 2013
New Revision: 178814

URL: http://llvm.org/viewvc/llvm-project?rev=178814&view=rev
Log:
[analyzer] Reduced the unwanted correlations between checkers living inside MallocChecker.cpp

This fixes an issue pointed to by Jordan: if unix.Malloc and unix.MismatchedDeallocator are both on, then we end up still tracking leaks of memory allocated by new.
Moved the guards right before emitting the bug reports to unify and simplify the logic of handling of multiple checkers. Now all the checkers perform their checks regardless of if they were enabled, or not, and it is decided just before the emitting of the report, if it should be emitted. (idea from Anna).

Additional changes: 
improved test coverage for checker correlations;
refactoring: BadDealloc -> MismatchedDealloc

Added:
    cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
    cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
    cfe/trunk/test/Analysis/Malloc+NewDelete_intersections.cpp
    cfe/trunk/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/test/Analysis/NewDelete-checker-test.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=178814&r1=178813&r2=178814&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Thu Apr  4 18:46:29 2013
@@ -149,7 +149,7 @@ class MallocChecker : public Checker<che
   mutable OwningPtr<BugType> BT_Leak;
   mutable OwningPtr<BugType> BT_UseFree;
   mutable OwningPtr<BugType> BT_BadFree;
-  mutable OwningPtr<BugType> BT_BadDealloc;
+  mutable OwningPtr<BugType> BT_MismatchedDealloc;
   mutable OwningPtr<BugType> BT_OffsetFree;
   mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
                          *II_valloc, *II_reallocf, *II_strndup, *II_strdup;
@@ -198,7 +198,7 @@ private:
   void initIdentifierInfo(ASTContext &C) const;
 
   /// \brief Determine family of a deallocation expression.
-  AllocationFamily getAllocationFamily(CheckerContext &C, const Expr *E) const;
+  AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const;
 
   /// \brief Print names of allocators and deallocators.
   ///
@@ -282,12 +282,19 @@ private:
                                   PointerEscapeKind Kind,
                                   bool(*CheckRefState)(const RefState*)) const;
 
+  // Used to suppress warnings if they are not related to the tracked family
+  // (derived from AllocDeallocStmt).
+  bool isTrackedFamily(AllocationFamily Family) const;
+  bool isTrackedFamily(CheckerContext &C, const Stmt *AllocDeallocStmt) const;
+  bool isTrackedFamily(CheckerContext &C, SymbolRef Sym) const;
+
   static bool SummarizeValue(raw_ostream &os, SVal V);
   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
   void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, 
                      const Expr *DeallocExpr) const;
-  void ReportBadDealloc(CheckerContext &C, SourceRange Range,
-                        const Expr *DeallocExpr, const RefState *RS) const;
+  void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
+                               const Expr *DeallocExpr, 
+                               const RefState *RS) const;
   void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, 
                         const Expr *DeallocExpr, 
                         const Expr *AllocExpr = 0) const;
@@ -558,45 +565,39 @@ void MallocChecker::checkPostStmt(const
     initIdentifierInfo(C.getASTContext());
     IdentifierInfo *FunI = FD->getIdentifier();
 
-    if (Filter.CMallocOptimistic || Filter.CMallocPessimistic ||
-        Filter.CMismatchedDeallocatorChecker) {
-      if (FunI == II_malloc || FunI == II_valloc) {
-        if (CE->getNumArgs() < 1)
-          return;
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-      } else if (FunI == II_realloc) {
-        State = ReallocMem(C, CE, false);
-      } else if (FunI == II_reallocf) {
-        State = ReallocMem(C, CE, true);
-      } else if (FunI == II_calloc) {
-        State = CallocMem(C, CE);
-      } else if (FunI == II_free) {
-        State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
-      } else if (FunI == II_strdup) {
-        State = MallocUpdateRefState(C, CE, State);
-      } else if (FunI == II_strndup) {
-        State = MallocUpdateRefState(C, CE, State);
-      }
+    if (FunI == II_malloc || FunI == II_valloc) {
+      if (CE->getNumArgs() < 1)
+        return;
+      State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+    } else if (FunI == II_realloc) {
+      State = ReallocMem(C, CE, false);
+    } else if (FunI == II_reallocf) {
+      State = ReallocMem(C, CE, true);
+    } else if (FunI == II_calloc) {
+      State = CallocMem(C, CE);
+    } else if (FunI == II_free) {
+      State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+    } else if (FunI == II_strdup) {
+      State = MallocUpdateRefState(C, CE, State);
+    } else if (FunI == II_strndup) {
+      State = MallocUpdateRefState(C, CE, State);
     }
-
-    if (Filter.CNewDeleteChecker || Filter.CMismatchedDeallocatorChecker) {
-      if (isStandardNewDelete(FD, C.getASTContext())) {
-        // Process direct calls to operator new/new[]/delete/delete[] functions
-        // as distinct from new/new[]/delete/delete[] expressions that are 
-        // processed by the checkPostStmt callbacks for CXXNewExpr and 
-        // CXXDeleteExpr.
-        OverloadedOperatorKind K = FD->getOverloadedOperator();
-        if (K == OO_New)
-          State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                               AF_CXXNew);
-        else if (K == OO_Array_New)
-          State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                               AF_CXXNewArray);
-        else if (K == OO_Delete || K == OO_Array_Delete)
-          State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
-        else
-          llvm_unreachable("not a new/delete operator");
-      }
+    else if (isStandardNewDelete(FD, C.getASTContext())) {
+      // Process direct calls to operator new/new[]/delete/delete[] functions
+      // as distinct from new/new[]/delete/delete[] expressions that are 
+      // processed by the checkPostStmt callbacks for CXXNewExpr and 
+      // CXXDeleteExpr.
+      OverloadedOperatorKind K = FD->getOverloadedOperator();
+      if (K == OO_New)
+        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+                             AF_CXXNew);
+      else if (K == OO_Array_New)
+        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+                             AF_CXXNewArray);
+      else if (K == OO_Delete || K == OO_Array_Delete)
+        State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+      else
+        llvm_unreachable("not a new/delete operator");
     }
   }
 
@@ -631,9 +632,6 @@ void MallocChecker::checkPostStmt(const
       if (SymbolRef Sym = C.getSVal(*I).getAsSymbol())
         checkUseAfterFree(Sym, C, *I);
 
-  if (!Filter.CNewDeleteChecker && !Filter.CMismatchedDeallocatorChecker)
-    return;
-
   if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
     return;
 
@@ -654,9 +652,6 @@ void MallocChecker::checkPreStmt(const C
     if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
       checkUseAfterFree(Sym, C, DE->getArgument());
 
-  if (!Filter.CNewDeleteChecker && !Filter.CMismatchedDeallocatorChecker)
-    return;
-
   if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext()))
     return;
 
@@ -838,32 +833,39 @@ static bool didPreviousFreeFail(ProgramS
 }
 
 AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, 
-                                                    const Expr *E) const {
-  if (!E)
+                                                    const Stmt *S) const {
+  if (!S)
     return AF_None;
 
-  if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
     const FunctionDecl *FD = C.getCalleeDecl(CE);
+
+    if (!FD)
+      FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
+
     ASTContext &Ctx = C.getASTContext();
 
-    if (isFreeFunction(FD, Ctx))
+    if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx))
       return AF_Malloc;
 
     if (isStandardNewDelete(FD, Ctx)) {
       OverloadedOperatorKind Kind = FD->getOverloadedOperator();
-      if (Kind == OO_Delete)
+      if (Kind == OO_New || Kind == OO_Delete)
         return AF_CXXNew;
-      else if (Kind == OO_Array_Delete)
+      else if (Kind == OO_Array_New || Kind == OO_Array_Delete)
         return AF_CXXNewArray;
     }
 
     return AF_None;
   }
 
-  if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E))
+  if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(S))
+    return NE->isArray() ? AF_CXXNewArray : AF_CXXNew;
+
+  if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(S))
     return DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew;
 
-  if (isa<ObjCMessageExpr>(E))
+  if (isa<ObjCMessageExpr>(S))
     return AF_Malloc;
 
   return AF_None;
@@ -1003,34 +1005,39 @@ ProgramStateRef MallocChecker::FreeMemAu
   const RefState *RsBase = State->get<RegionState>(SymBase);
   SymbolRef PreviousRetStatusSymbol = 0;
 
-  // Check double free.
-  if (RsBase &&
-      (RsBase->isReleased() || RsBase->isRelinquished()) &&
-      !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
-    ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
-                     SymBase, PreviousRetStatusSymbol);
-    return 0;
-  }
+  if (RsBase) {
 
-  // Check if an expected deallocation function matches the real one.
-  if (RsBase && 
-      RsBase->getAllocationFamily() != AF_None &&
-      RsBase->getAllocationFamily() != getAllocationFamily(C, ParentExpr) ) {
-    ReportBadDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase);
-    return 0;
-  }
+    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);
+      return 0;
+    }
 
-  // Check if the memory location being freed is the actual location
-  // allocated, or an offset.
-  RegionOffset Offset = R->getAsOffset();
-  if (RsBase && 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;
+    // Check double free.
+    if (DeallocMatchesAlloc &&
+        (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;
+    }
   }
 
   ReleasedAllocated = (RsBase != 0);
@@ -1060,6 +1067,30 @@ ProgramStateRef MallocChecker::FreeMemAu
                                  RefState::getReleased(Family, ParentExpr));
 }
 
+bool MallocChecker::isTrackedFamily(AllocationFamily Family) const {
+  if (Family == AF_Malloc &&
+    (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic))
+    return false;
+
+  if ((Family == AF_CXXNew || Family == AF_CXXNewArray) &&
+    !Filter.CNewDeleteChecker)
+    return false;
+
+  return true;
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C, 
+                                    const Stmt *AllocDeallocStmt) const {
+  return isTrackedFamily(getAllocationFamily(C, AllocDeallocStmt));
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C, SymbolRef Sym) const {
+  const RefState *RS = C.getState()->get<RegionState>(Sym);
+
+  return RS ? isTrackedFamily(RS->getAllocationFamily()) 
+            : isTrackedFamily(AF_None);
+}
+
 bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
   if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>())
     os << "an integer (" << IntVal->getValue() << ")";
@@ -1155,6 +1186,9 @@ void MallocChecker::ReportBadFree(Checke
       !Filter.CNewDeleteChecker)
     return;
 
+  if (!isTrackedFamily(C, DeallocExpr))
+    return;
+
   if (ExplodedNode *N = C.generateSink()) {
     if (!BT_BadFree)
       BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
@@ -1191,16 +1225,18 @@ void MallocChecker::ReportBadFree(Checke
   }
 }
 
-void MallocChecker::ReportBadDealloc(CheckerContext &C, SourceRange Range,
-                                     const Expr *DeallocExpr, 
-                                     const RefState *RS) const {
+void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, 
+                                            SourceRange Range,
+                                            const Expr *DeallocExpr, 
+                                            const RefState *RS) const {
 
   if (!Filter.CMismatchedDeallocatorChecker)
     return;
 
   if (ExplodedNode *N = C.generateSink()) {
-    if (!BT_BadDealloc)
-      BT_BadDealloc.reset(new BugType("Bad deallocator", "Memory Error"));
+    if (!BT_MismatchedDealloc)
+      BT_MismatchedDealloc.reset(new BugType("Bad deallocator",
+                                             "Memory Error"));
     
     SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
@@ -1221,7 +1257,7 @@ void MallocChecker::ReportBadDealloc(Che
     if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
       os << ", not " << DeallocOs.str();
 
-    BugReport *R = new BugReport(*BT_BadDealloc, os.str(), N);
+    BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N);
     R->addRange(Range);
     C.emitReport(R);
   }
@@ -1235,6 +1271,9 @@ void MallocChecker::ReportOffsetFree(Che
       !Filter.CNewDeleteChecker)
     return;
 
+  if (!isTrackedFamily(C, AllocExpr))
+    return;
+
   ExplodedNode *N = C.generateSink();
   if (N == NULL)
     return;
@@ -1284,6 +1323,9 @@ void MallocChecker::ReportUseAfterFree(C
       !Filter.CNewDeleteChecker)
     return;
 
+  if (!isTrackedFamily(C, Sym))
+    return;
+
   if (ExplodedNode *N = C.generateSink()) {
     if (!BT_UseFree)
       BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
@@ -1306,6 +1348,9 @@ void MallocChecker::ReportDoubleFree(Che
       !Filter.CNewDeleteChecker)
     return;
 
+  if (!isTrackedFamily(C, Sym))
+    return;
+
   if (ExplodedNode *N = C.generateSink()) {
     if (!BT_DoubleFree)
       BT_DoubleFree.reset(new BugType("Double free", "Memory Error"));
@@ -1507,10 +1552,13 @@ void MallocChecker::reportLeak(SymbolRef
     AllocationStmt = Exit->getCalleeContext()->getCallSite();
   else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
     AllocationStmt = SP->getStmt();
-  if (AllocationStmt)
+  if (AllocationStmt) {
     LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
                                               C.getSourceManager(),
                                               AllocNode->getLocationContext());
+    if (!isTrackedFamily(C, AllocationStmt))
+      return;
+  }
 
   SmallString<200> buf;
   llvm::raw_svector_ostream os(buf);

Added: cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator%2BNewDelete.cpp?rev=178814&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp (added)
+++ cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp Thu Apr  4 18:46:29 2013
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------
+// Check that unix.Malloc catches all types of bugs.
+//--------------------------------------------------
+void testMallocDoubleFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(p);
+  free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void testMallocLeak() {
+  int *p = (int *)malloc(sizeof(int));
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testMallocUseAfterFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(p);
+  int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testMallocBadFree() {
+  int i;
+  free(&i); // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
+}
+
+void testMallocOffsetFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(++p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
+}
+
+//-----------------------------------------------------------------
+// Check that unix.MismatchedDeallocator catches all types of bugs.
+//-----------------------------------------------------------------
+void testMismatchedDeallocator() {
+  int *x = (int *)malloc(sizeof(int));
+  delete x; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+//----------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete catches all types of bugs.
+//----------------------------------------------------------------
+void testNewDoubleFree() {
+  int *p = new int;
+  delete p;
+  delete p; // expected-warning{{Attempt to free released memory}}
+}
+
+void testNewLeak() {
+  int *p = new int;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testNewUseAfterFree() {
+  int *p = (int *)operator new(0);
+  delete p;
+  int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testNewBadFree() {
+  int i;
+  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
+}
+
+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'}}
+}

Added: cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator_intersections.cpp?rev=178814&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp (added)
+++ cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp Thu Apr  4 18:46:29 2013
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------------------------
+// Check that unix.Malloc + unix.MismatchedDeallocator does not enable
+// warnings produced by the alpha.cplusplus.NewDelete checker.
+//--------------------------------------------------------------------
+void testNewDeleteNoWarn() {
+  int i;
+  delete &i; // no-warning
+
+  int *p1 = new int;
+  delete ++p1; // no-warning
+
+  int *p2 = new int;
+  delete p2;
+  delete p2; // no-warning
+
+  int *p3 = new int; // no-warning
+
+  int *p4 = new int;
+  delete p4;
+  int j = *p4; // no-warning  
+}

Added: cfe/trunk/test/Analysis/Malloc+NewDelete_intersections.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BNewDelete_intersections.cpp?rev=178814&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/Malloc+NewDelete_intersections.cpp (added)
+++ cfe/trunk/test/Analysis/Malloc+NewDelete_intersections.cpp Thu Apr  4 18:46:29 2013
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//-------------------------------------------------------------------
+// Check that unix.Malloc + alpha.cplusplus.NewDelete does not enable
+// warnings produced by unix.MismatchedDeallocator.
+//-------------------------------------------------------------------
+void testMismatchedDeallocator() {
+  int *p = (int *)malloc(sizeof(int));
+  delete p;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}

Added: cfe/trunk/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/NewDelete%2BMismatchedDeallocator_intersections.cpp?rev=178814&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp (added)
+++ cfe/trunk/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp Thu Apr  4 18:46:29 2013
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//------------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete + unix.MismatchedDeallocator 
+// does not enable warnings produced by the unix.Malloc checker.
+//------------------------------------------------------------------
+void testMallocFreeNoWarn() {
+  int i;
+  free(&i); // no warn
+
+  int *p1 = (int *)malloc(sizeof(int));
+  free(++p1); // no warn
+
+  int *p2 = (int *)malloc(sizeof(int));
+  free(p2);
+  free(p2); // no warn
+
+  int *p3 = (int *)malloc(sizeof(int)); // no warn
+
+  int *p4 = (int *)malloc(sizeof(int));
+  free(p4);
+  int j = *p4; // no warn
+}

Modified: cfe/trunk/test/Analysis/NewDelete-checker-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/NewDelete-checker-test.cpp?rev=178814&r1=178813&r2=178814&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/NewDelete-checker-test.cpp (original)
+++ cfe/trunk/test/Analysis/NewDelete-checker-test.cpp Thu Apr  4 18:46:29 2013
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.Malloc -analyzer-store region -std=c++11 -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -fblocks -verify %s
 #include "Inputs/system-header-simulator-cxx.h"
 
 typedef __typeof__(sizeof(int)) size_t;





More information about the cfe-commits mailing list