aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-12-20 00:38:25 +0000
committerAnna Zaks <ganna@apple.com>2012-12-20 00:38:25 +0000
commitbf53dfac8195835028bd6347433f7dbebcc29fc1 (patch)
tree52e15cb639417b3c9a1df69fb37c4221ee680ba3 /lib/StaticAnalyzer/Checkers/MallocChecker.cpp
parentb29740ae158f9421096a28bcc7ad6af7171b1874 (diff)
[analyzer] Add the pointer escaped callback.
Instead of using several callbacks to identify the pointer escape event, checkers now can register for the checkPointerEscape. Converted the Malloc checker to use the new callback. SimpleStreamChecker will be converted next. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170625 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp105
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);