diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/Environment.h | 1 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRState.h | 10 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/SymbolManager.h | 9 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 40 | ||||
-rw-r--r-- | lib/Analysis/Environment.cpp | 22 | ||||
-rw-r--r-- | lib/Analysis/GRState.cpp | 31 | ||||
-rw-r--r-- | lib/Analysis/SymbolManager.cpp | 3 | ||||
-rw-r--r-- | test/Analysis/rdar-6582778-basic-store.c | 22 |
8 files changed, 115 insertions, 23 deletions
diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h index 7613c9ea5f..5c702d659c 100644 --- a/include/clang/Analysis/PathSensitive/Environment.h +++ b/include/clang/Analysis/PathSensitive/Environment.h @@ -141,6 +141,7 @@ public: Environment RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper, + GRStateManager& StateMgr, llvm::SmallVectorImpl<const MemRegion*>& DRoots); }; diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index b227f91a78..ac0908cf1f 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -610,6 +610,9 @@ public: void EndPath(const GRState* St) { ConstraintMgr->EndPath(St); } + + bool scanReachableSymbols(nonloc::CompoundVal val, SymbolVisitor& vistor); + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor); }; //===----------------------------------------------------------------------===// @@ -732,6 +735,13 @@ public: return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr); } + template <typename CB> + CB scanReachableSymbols(SVal val) { + CB cb(*this); + Mgr->scanReachableSymbols(val, cb); + return cb; + } + // Pretty-printing. void print(std::ostream& Out, const char* nl = "\n", const char *sep = "") const; diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h index 6b777be0c5..18c177bdd6 100644 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -263,6 +263,15 @@ public: } }; +class SymbolVisitor { +public: + // VisitSymbol - A visitor method invoked by + // GRStateManager::scanReachableSymbols. The method returns \c true if + // symbols should continue be scanned and \c false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual ~SymbolVisitor(); +}; + } // end clang namespace #endif diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 875c4e39b8..81faf21653 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -21,6 +21,7 @@ #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -1736,13 +1737,25 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), Summ, ME->arg_begin(), ME->arg_end(), Pred); } + +namespace { +class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor { + GRStateRef state; +public: + StopTrackingCallback(GRStateRef st) : state(st) {} + GRStateRef getState() { return state; } + + bool VisitSymbol(SymbolRef sym) { + state = state.remove<RefBindings>(sym); + return true; + } -void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { - // Check if we have a binding for "Val" and if we are storing it to something - // we don't understand or otherwise the value "escapes" the function. - if (!isa<loc::SymbolVal>(val)) - return; + const GRState* getState() const { return state.getState(); } +}; +} // end anonymous namespace + +void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { // Are we storing to something that causes the value to "escape"? bool escapes = false; @@ -1752,7 +1765,6 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { // (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. - SymbolRef Sym = cast<loc::SymbolVal>(val).getSymbol(); GRStateRef state = B.getState(); if (!isa<loc::MemRegionVal>(location)) @@ -1769,15 +1781,15 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { } } - // Our store can represent the binding and we aren't storing to something - // that doesn't have local storage. Just return and have the simulation - // state continue as is. We should also just return if the tracked symbol - // is not associated with a reference count. - if (!escapes || !state.get<RefBindings>(Sym)) - return; + // 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; - // The tracked object excapes. Stop tracking the object. - B.MakeNode(state.remove<RefBindings>(Sym)); + // Otherwise, find all symbols referenced by 'val' that we are tracking + // and stop tracking them. + B.MakeNode(state.scanReachableSymbols<StopTrackingCallback>(val).getState()); } std::pair<GRStateRef,bool> diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index c4ed349906..e3ed678d5e 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -10,11 +10,11 @@ // This file defined the Environment and EnvironmentManager classes. // //===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/Environment.h" +#include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Streams.h" +#include "llvm/Support/Compiler.h" using namespace clang; @@ -106,9 +106,19 @@ Environment EnvironmentManager::BindExpr(const Environment& Env, Stmt* E,SVal V, return isBlkExpr ? AddBlkExpr(Env, E, V) : AddSubExpr(Env, E, V); } +namespace { +class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor { + SymbolReaper &SymReaper; +public: + MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} + bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; } +}; +} // end anonymous namespace + Environment EnvironmentManager::RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper, + GRStateManager& StateMgr, llvm::SmallVectorImpl<const MemRegion*>& DRoots) { // Drop bindings for subexpressions. @@ -126,11 +136,9 @@ EnvironmentManager::RemoveDeadBindings(Environment Env, Stmt* Loc, if (isa<loc::MemRegionVal>(X)) DRoots.push_back(cast<loc::MemRegionVal>(X).getRegion()); - // Mark all symbols in the block expr's value. - for (SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); - SI != SE; ++SI) - SymReaper.markLive(*SI); - + // Mark all symbols in the block expr's value live. + MarkLiveCallback cb(SymReaper); + StateMgr.scanReachableSymbols(X, cb); } else { // The block expr is dead. SVal X = I.getData(); diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index ea6f7a03d6..0788b432ba 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -45,7 +45,7 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, llvm::SmallVector<const MemRegion*, 10> RegionRoots; GRState NewState = *state; - NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, + NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, *this, RegionRoots); // Clean up the store. @@ -205,6 +205,35 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ } //===----------------------------------------------------------------------===// +// Utility. +//===----------------------------------------------------------------------===// + +bool GRStateManager::scanReachableSymbols(nonloc::CompoundVal val, + SymbolVisitor& visitor) { + for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I) + if (!scanReachableSymbols(*I, visitor)) return false; + + return true; +} + +bool GRStateManager::scanReachableSymbols(SVal val, SymbolVisitor& visitor) { + + // FIXME: Scan through through the reachable regions. + // if (isa<Loc>(val)) { ... } + + if (loc::SymbolVal *X = dyn_cast<loc::SymbolVal>(&val)) + return visitor.VisitSymbol(X->getSymbol()); + + if (nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(&val)) + return visitor.VisitSymbol(X->getSymbol()); + + if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val)) + return scanReachableSymbols(*X, visitor); + + return true; +} + +//===----------------------------------------------------------------------===// // Queries. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp index 1672af8c61..f1c1cc0a46 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Analysis/SymbolManager.cpp @@ -99,4 +99,5 @@ bool SymbolReaper::isLive(SymbolRef sym) { // the analyzed function/method. return isa<SymbolRegionRValue>(SymMgr.getSymbolData(sym)); } - + +SymbolVisitor::~SymbolVisitor() {} diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c new file mode 100644 index 0000000000..c0a599335b --- /dev/null +++ b/test/Analysis/rdar-6582778-basic-store.c @@ -0,0 +1,22 @@ +// RUN: clang -analyze -checker-cfref -analyzer-store-basic -verify %s + +typedef const void * CFTypeRef; +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +typedef const struct __CFAllocator * CFAllocatorRef; +typedef const struct __CFDate * CFDateRef; + +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); + +void f(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFTypeRef vals[] = { CFDateCreate(0, t) }; // no-warning +} + +CFTypeRef global; + +void g(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + global = CFDateCreate(0, t); // no-warning +} |