diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 105 |
1 files changed, 16 insertions, 89 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 26fd1c26ea..af902a0096 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -103,15 +103,14 @@ struct ReallocPair { typedef std::pair<const Stmt*, const MemRegion*> LeakInfo; class MallocChecker : public Checker<check::DeadSymbols, + check::PointerEscape, check::PreStmt<ReturnStmt>, check::PreStmt<CallExpr>, check::PostStmt<CallExpr>, check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location, - check::Bind, - eval::Assume, - check::RegionChanges> + eval::Assume> { mutable OwningPtr<BugType> BT_DoubleFree; mutable OwningPtr<BugType> BT_Leak; @@ -143,17 +142,10 @@ public: bool Assumption) const; void checkLocation(SVal l, bool isLoad, const Stmt *S, CheckerContext &C) const; - void checkBind(SVal location, SVal val, const Stmt*S, - CheckerContext &C) const; - ProgramStateRef - checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, - ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) const; - bool wantsRegionChangeUpdate(ProgramStateRef state) const { - return true; - } + + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const; @@ -1254,51 +1246,6 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, checkUseAfterFree(Sym, C, S); } -//===----------------------------------------------------------------------===// -// Check various ways a symbol can be invalidated. -// TODO: This logic (the next 3 functions) is copied/similar to the -// RetainRelease checker. We might want to factor this out. -//===----------------------------------------------------------------------===// - -// Stop tracking symbols when a value escapes as a result of checkBind. -// A value escapes in three possible cases: -// (1) we are binding to something that is not a memory region. -// (2) we are binding to a memregion that does not have stack storage -// (3) we are binding to a memregion with stack storage that the store -// does not understand. -void MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S, - CheckerContext &C) const { - // Are we storing to something that causes the value to "escape"? - bool escapes = true; - ProgramStateRef state = C.getState(); - - if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) { - escapes = !regionLoc->getRegion()->hasStackStorage(); - - if (!escapes) { - // To test (3), generate a new state with the binding added. If it is - // the same state, then it escapes (since the store cannot represent - // the binding). - // Do this only if we know that the store is not supposed to generate the - // same state. - SVal StoredVal = state->getSVal(regionLoc->getRegion()); - if (StoredVal != val) - escapes = (state == (state->bindLoc(*regionLoc, val))); - } - } - - // If our store can represent the binding and we aren't storing to something - // that doesn't have local storage then just return and have the simulation - // state continue as is. - if (!escapes) - return; - - // Otherwise, find all symbols referenced by 'val' that we are tracking - // and stop tracking them. - state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); - C.addTransition(state); -} - // If a symbolic region is assumed to NULL (or another constant), stop tracking // it - assuming that allocation failed on this path. ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, @@ -1485,39 +1432,19 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call, return true; } -// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p -// escapes, when we are tracking p), do not track the symbol as we cannot reason -// about it anymore. -ProgramStateRef -MallocChecker::checkRegionChanges(ProgramStateRef State, - const StoreManager::InvalidatedSymbols *invalidated, - ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) const { - if (!invalidated || invalidated->empty()) +ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) const { + // If we know that the call does not free memory, keep tracking the top + // level arguments. + if (Call && doesNotFreeMemory(Call, State)) return State; - llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; - - // If it's a call which might free or reallocate memory, we assume that all - // regions (explicit and implicit) escaped. - // Otherwise, whitelist explicit pointers; we still can track them. - if (!Call || doesNotFreeMemory(Call, State)) { - for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), - E = ExplicitRegions.end(); I != E; ++I) { - if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>()) - WhitelistedSymbols.insert(R->getSymbol()); - } - } - - for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), - E = invalidated->end(); I!=E; ++I) { + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); + I != E; ++I) { SymbolRef sym = *I; - if (WhitelistedSymbols.count(sym)) - continue; - // The symbol escaped. Note, we assume that if the symbol is released, - // passing it out will result in a use after free. We also keep tracking - // relinquished symbols. + if (const RefState *RS = State->get<RegionState>(sym)) { if (RS->isAllocated()) State = State->remove<RegionState>(sym); |