]> granicus.if.org Git - clang/commitdiff
[analyzer] Fix another false positive in malloc realloc logic.
authorAnna Zaks <ganna@apple.com>
Wed, 12 Sep 2012 22:57:34 +0000 (22:57 +0000)
committerAnna Zaks <ganna@apple.com>
Wed, 12 Sep 2012 22:57:34 +0000 (22:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163749 91177308-0d34-0410-b5e6-96231b3b80d8

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

index b3107c84476e8b3da52f27005afe3cbd1f4aa816..f57ea12ee07632faaca1072d070f78b849caea07 100644 (file)
@@ -70,24 +70,31 @@ public:
   }
 };
 
+enum ReallocPairKind {
+  RPToBeFreedAfterFailure,
+  // The symbol has been freed when reallocation failed.
+  RPIsFreeOnFailure,
+  // The symbol does not need to be freed after reallocation fails.
+  RPDoNotTrackAfterFailure
+};
+
 /// \class ReallocPair
 /// \brief Stores information about the symbol being reallocated by a call to
 /// 'realloc' to allow modeling failed reallocation later in the path.
 struct ReallocPair {
   // \brief The symbol which realloc reallocated.
   SymbolRef ReallocatedSym;
-  // \brief The flag is true if the symbol does not need to be freed after
-  // reallocation fails.
-  bool IsFreeOnFailure;
+  ReallocPairKind Kind;
 
-  ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+  ReallocPair(SymbolRef S, ReallocPairKind K) :
+    ReallocatedSym(S), Kind(K) {}
   void Profile(llvm::FoldingSetNodeID &ID) const {
-    ID.AddInteger(IsFreeOnFailure);
+    ID.AddInteger(Kind);
     ID.AddPointer(ReallocatedSym);
   }
   bool operator==(const ReallocPair &X) const {
     return ReallocatedSym == X.ReallocatedSym &&
-           IsFreeOnFailure == X.IsFreeOnFailure;
+           Kind == X.Kind;
   }
 };
 
@@ -926,10 +933,16 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
     if (!stateRealloc)
       return 0;
 
+    ReallocPairKind Kind = RPToBeFreedAfterFailure;
+    if (FreesOnFail)
+      Kind = RPIsFreeOnFailure;
+    else if (!ReleasedAllocated)
+      Kind = RPDoNotTrackAfterFailure;
+
     // Record the info about the reallocated symbol so that we could properly
     // process failed reallocation.
     stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
-                     ReallocPair(FromPtr, FreesOnFail || !ReleasedAllocated));
+                                                   ReallocPair(FromPtr, Kind));
     // The reallocated symbol should stay alive for as long as the new symbol.
     C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
     return stateRealloc;
@@ -1285,15 +1298,21 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
   ReallocMap RP = state->get<ReallocPairs>();
   for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
     // If the symbol is assumed to be NULL, remove it from consideration.
-    if (state->getConstraintManager().isNull(state, I.getKey()).isTrue()) {
-      SymbolRef ReallocSym = I.getData().ReallocatedSym;
-      if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
-        if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+    if (!state->getConstraintManager().isNull(state, I.getKey()).isTrue())
+      continue;
+    SymbolRef ReallocSym = I.getData().ReallocatedSym;
+    if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
+      if (RS->isReleased()) {
+        if (I.getData().Kind == RPToBeFreedAfterFailure)
           state = state->set<RegionState>(ReallocSym,
-                             RefState::getAllocated(RS->getStmt()));
+              RefState::getAllocated(RS->getStmt()));
+        else if (I.getData().Kind == RPDoNotTrackAfterFailure)
+          state = state->remove<RegionState>(ReallocSym);
+        else
+          assert(I.getData().Kind == RPIsFreeOnFailure);
       }
-      state = state->remove<ReallocPairs>(I.getKey());
     }
+    state = state->remove<ReallocPairs>(I.getKey());
   }
 
   return state;
index 52a79243ce4e3e1ccd2aef57eed9dd0bbd62ad7f..b939ac36d1ac846fcfc6258866b94c75af5817c3 100644 (file)
@@ -1020,6 +1020,16 @@ int reallocButNoMallocPR13674(struct HasPtr *a, int c, int size) {
   return 0;
 }
 
+// Test realloc with no visible malloc.
+void *test(void *ptr) {
+  void *newPtr = realloc(ptr, 4);
+  if (newPtr == 0) {
+    if (ptr)
+      free(ptr); // no-warning
+  }
+  return newPtr;
+}
+
 // ----------------------------------------------------------------------------
 // False negatives.