[cfe-commits] r150533 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/MallocChecker.cpp test/Analysis/malloc.c

Anna Zaks ganna at apple.com
Tue Feb 14 16:11:25 PST 2012


Author: zaks
Date: Tue Feb 14 18:11:25 2012
New Revision: 150533

URL: http://llvm.org/viewvc/llvm-project?rev=150533&view=rev
Log:
[analyzer] Malloc Checker: add support for reallocf, which always frees
the passed in pointer on failure.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.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=150533&r1=150532&r2=150533&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Tue Feb 14 18:11:25 2012
@@ -67,6 +67,20 @@
   }
 };
 
+struct ReallocPair {
+  SymbolRef ReallocatedSym;
+  bool IsFreeOnFailure;
+  ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(IsFreeOnFailure);
+    ID.AddPointer(ReallocatedSym);
+  }
+  bool operator==(const ReallocPair &X) const {
+    return ReallocatedSym == X.ReallocatedSym &&
+           IsFreeOnFailure == X.IsFreeOnFailure;
+  }
+};
+
 class MallocChecker : public Checker<check::DeadSymbols,
                                      check::EndPath,
                                      check::PreStmt<ReturnStmt>,
@@ -83,11 +97,11 @@
   mutable OwningPtr<BuiltinBug> BT_UseRelinquished;
   mutable OwningPtr<BuiltinBug> BT_BadFree;
   mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
-                         *II_valloc;
+                         *II_valloc, *II_reallocf;
 
 public:
   MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0),
-                    II_valloc(0) {}
+                    II_valloc(0), II_reallocf(0) {}
 
   /// In pessimistic mode, the checker assumes that it does not know which
   /// functions might free the memory.
@@ -147,7 +161,8 @@
                                  ProgramStateRef state, unsigned Num,
                                  bool Hold) const;
 
-  void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
+  void ReallocMem(CheckerContext &C, const CallExpr *CE,
+                  bool FreesMemOnFailure) const;
   static void CallocMem(CheckerContext &C, const CallExpr *CE);
   
   bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const;
@@ -201,7 +216,7 @@
 } // end anonymous namespace
 
 typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-typedef llvm::ImmutableMap<SymbolRef, SymbolRef> SymRefToSymRefTy;
+typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
 class RegionState {};
 class ReallocPairs {};
 namespace clang {
@@ -214,7 +229,7 @@
 
   template <>
   struct ProgramStateTrait<ReallocPairs>
-    : public ProgramStatePartialTrait<SymRefToSymRefTy> {
+    : public ProgramStatePartialTrait<ReallocMap> {
     static void *GDMIndex() { static int x; return &x; }
   };
 }
@@ -241,6 +256,8 @@
     II_free = &Ctx.Idents.get("free");
   if (!II_realloc)
     II_realloc = &Ctx.Idents.get("realloc");
+  if (!II_reallocf)
+    II_reallocf = &Ctx.Idents.get("reallocf");
   if (!II_calloc)
     II_calloc = &Ctx.Idents.get("calloc");
   if (!II_valloc)
@@ -254,8 +271,8 @@
     return false;
 
   // TODO: Add more here : ex: reallocf!
-  if (FunI == II_malloc || FunI == II_free ||
-      FunI == II_realloc || FunI == II_calloc || FunI == II_valloc)
+  if (FunI == II_malloc || FunI == II_free || FunI == II_realloc ||
+      FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc)
     return true;
 
   if (Filter.CMallocOptimistic && FD->hasAttrs() &&
@@ -281,7 +298,10 @@
     MallocMem(C, CE);
     return;
   } else if (FunI == II_realloc) {
-    ReallocMem(C, CE);
+    ReallocMem(C, CE, false);
+    return;
+  } else if (FunI == II_reallocf) {
+    ReallocMem(C, CE, true);
     return;
   } else if (FunI == II_calloc) {
     CallocMem(C, CE);
@@ -616,7 +636,8 @@
   }
 }
 
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE,
+                               bool FreesOnFail) const {
   ProgramStateRef state = C.getState();
   const Expr *arg0Expr = CE->getArg(0);
   const LocationContext *LCtx = C.getLocationContext();
@@ -681,7 +702,8 @@
       // 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, FromPtr);
+      stateFree = stateFree->set<ReallocPairs>(ToPtr,
+                                            ReallocPair(FromPtr, FreesOnFail));
       C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
       C.addTransition(stateFree);
       return;
@@ -694,7 +716,8 @@
                                                 UnknownVal(), stateFree);
     if (!stateRealloc)
       return;
-    stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr);
+    stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
+                                            ReallocPair(FromPtr, FreesOnFail));
     C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
     C.addTransition(stateRealloc);
     return;
@@ -758,9 +781,10 @@
   }
   
   // Cleanup the Realloc Pairs Map.
-  SymRefToSymRefTy RP = state->get<ReallocPairs>();
-  for (SymRefToSymRefTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
-    if (SymReaper.isDead(I->first) || SymReaper.isDead(I->second)) {
+  ReallocMap RP = state->get<ReallocPairs>();
+  for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+    if (SymReaper.isDead(I->first) ||
+        SymReaper.isDead(I->second.ReallocatedSym)) {
       state = state->remove<ReallocPairs>(I->first);
     }
   }
@@ -926,19 +950,17 @@
 
   // Realloc returns 0 when reallocation fails, which means that we should
   // restore the state of the pointer being reallocated.
-  SymRefToSymRefTy RP = state->get<ReallocPairs>();
-  for (SymRefToSymRefTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+  ReallocMap RP = state->get<ReallocPairs>();
+  for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
     // If the symbol is assumed to NULL or another constant, this will
     // return an APSInt*.
     if (state->getSymVal(I.getKey())) {
-      const RefState *RS = state->get<RegionState>(I.getData());
+      SymbolRef ReallocSym = I.getData().ReallocatedSym;
+      const RefState *RS = state->get<RegionState>(ReallocSym);
       if (RS) {
-        if (RS->isReleased())
-          state = state->set<RegionState>(I.getData(),
+        if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+          state = state->set<RegionState>(ReallocSym,
                              RefState::getAllocateUnchecked(RS->getStmt()));
-        else if (RS->isAllocated())
-          state = state->set<RegionState>(I.getData(),
-                             RefState::getReleased(RS->getStmt()));
       }
       state = state->remove<ReallocPairs>(I.getKey());
     }

Modified: cfe/trunk/test/Analysis/malloc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/malloc.c?rev=150533&r1=150532&r2=150533&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/malloc.c (original)
+++ cfe/trunk/test/Analysis/malloc.c Tue Feb 14 18:11:25 2012
@@ -6,6 +6,7 @@
 void *valloc(size_t);
 void free(void *);
 void *realloc(void *ptr, size_t size);
+void *reallocf(void *ptr, size_t size);
 void *calloc(size_t nmemb, size_t size);
 
 void myfoo(int *p);
@@ -151,6 +152,39 @@
     }
 }
 
+int *reallocfTest1() {
+  int *q = malloc(12);
+  q = reallocf(q, 20);
+  return q; // no warning - returning the allocated value
+}
+
+void reallocfRadar6337483_4() {
+    char *buf = malloc(100);
+    char *buf2 = (char*)reallocf(buf, 0x1000000);
+    if (!buf2) {
+      return;  // no warning - reallocf frees even on failure
+    } else {
+      free(buf2);
+    }
+}
+
+void reallocfRadar6337483_3() {
+    char * buf = malloc(100);
+    char * tmp;
+    tmp = (char*)reallocf(buf, 0x1000000);
+    if (!tmp) {
+        free(buf); // expected-warning {{Try to free a memory block that has been released}}
+        return;
+    }
+    buf = tmp;
+    free(buf);
+}
+
+void reallocfPtrZero1() {
+  char *r = reallocf(0, 12); // expected-warning {{Allocated memory never released.}}
+}
+
+
 // This case tests that storing malloc'ed memory to a static variable which is
 // then returned is not leaked.  In the absence of known contracts for functions
 // or inter-procedural analysis, this is a conservative answer.





More information about the cfe-commits mailing list