Environment
RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
+ GRStateManager& StateMgr,
llvm::SmallVectorImpl<const MemRegion*>& DRoots);
};
void EndPath(const GRState* St) {
ConstraintMgr->EndPath(St);
}
+
+ bool scanReachableSymbols(nonloc::CompoundVal val, SymbolVisitor& vistor);
+ bool scanReachableSymbols(SVal val, SymbolVisitor& visitor);
};
//===----------------------------------------------------------------------===//
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;
}
};
+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
#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"
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;
// (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))
}
}
- // 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>
// 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;
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.
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();
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.
return getPersistentState(NewSt);
}
+//===----------------------------------------------------------------------===//
+// 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.
//===----------------------------------------------------------------------===//
// the analyzed function/method.
return isa<SymbolRegionRValue>(SymMgr.getSymbolData(sym));
}
-
+
+SymbolVisitor::~SymbolVisitor() {}
--- /dev/null
+// 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
+}