Add a callback for when region changes occur. Still somewhat of a work-in-progress, but working! Effect on clients: all changes to a store now go through GRState.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111078 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 7d01c9e..a5e87e4 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -52,7 +52,7 @@
Store InvalidateRegions(Store store, const MemRegion * const *Begin,
const MemRegion * const *End, const Expr *E,
unsigned Count, InvalidatedSymbols *IS,
- bool invalidateGlobals);
+ bool invalidateGlobals, InvalidatedRegions *Regions);
Store scanForIvars(Stmt *B, const Decl* SelfDecl,
const MemRegion *SelfRegion, Store St);
@@ -521,11 +521,12 @@
Store BasicStoreManager::InvalidateRegions(Store store,
- const MemRegion * const *I,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
- bool invalidateGlobals) {
+ const MemRegion * const *I,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS,
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions) {
if (invalidateGlobals) {
BindingsTy B = GetBindings(store);
for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) {
@@ -543,6 +544,8 @@
continue;
}
store = InvalidateRegion(store, *I, E, Count, IS);
+ if (Regions)
+ Regions->push_back(R);
}
// FIXME: This is copy-and-paste from RegionStore.cpp.
@@ -556,6 +559,8 @@
Count);
store = Bind(store, loc::MemRegionVal(GS), V);
+ if (Regions)
+ Regions->push_back(GS);
}
return store;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
index 64c6ed0..46e2477 100644
--- a/lib/Checker/FlatStore.cpp
+++ b/lib/Checker/FlatStore.cpp
@@ -60,7 +60,7 @@
Store InvalidateRegions(Store store, const MemRegion * const *I,
const MemRegion * const *E, const Expr *Ex,
unsigned Count, InvalidatedSymbols *IS,
- bool invalidateGlobals);
+ bool invalidateGlobals, InvalidatedRegions *Regions);
void print(Store store, llvm::raw_ostream& Out, const char* nl,
const char *sep);
@@ -155,11 +155,12 @@
}
Store FlatStoreManager::InvalidateRegions(Store store,
- const MemRegion * const *I,
- const MemRegion * const *E,
- const Expr *Ex, unsigned Count,
- InvalidatedSymbols *IS,
- bool invalidateGlobals) {
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count,
+ InvalidatedSymbols *IS,
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions) {
assert(false && "Not implemented");
return store;
}
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index fe19c05..e306ac6 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -557,6 +557,75 @@
return TF->EvalAssume(state, cond, assumption);
}
+bool GRExprEngine::WantsRegionChangeUpdate(const GRState* state) {
+ CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+ CheckersOrdered *CO = COCache[K];
+
+ if (!CO)
+ CO = &Checkers;
+
+ for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+ Checker *C = I->second;
+ if (C->WantsRegionChangeUpdate(state))
+ return true;
+ }
+
+ return false;
+}
+
+const GRState *
+GRExprEngine::ProcessRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) {
+ // FIXME: Most of this method is copy-pasted from ProcessAssume.
+
+ // Determine if we already have a cached 'CheckersOrdered' vector
+ // specifically tailored for processing region changes. This
+ // can reduce the number of checkers actually called.
+ CheckersOrdered *CO = &Checkers;
+ llvm::OwningPtr<CheckersOrdered> NewCO;
+
+ CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+ CheckersOrdered *& CO_Ref = COCache[K];
+
+ if (!CO_Ref) {
+ // If we have no previously cached CheckersOrdered vector for this
+ // callback, then create one.
+ NewCO.reset(new CheckersOrdered);
+ }
+ else {
+ // Use the already cached set.
+ CO = CO_Ref;
+ }
+
+ // If there are no checkers, just return the state as is.
+ if (CO->empty())
+ return state;
+
+ for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+ // If any checker declares the state infeasible (or if it starts that way),
+ // bail out.
+ if (!state)
+ return NULL;
+
+ Checker *C = I->second;
+ bool respondsToCallback = true;
+
+ state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback);
+
+ // See if we're building a cache of checkers that care about region changes.
+ if (NewCO.get() && respondsToCallback)
+ NewCO->push_back(*I);
+ }
+
+ // If we got through all the checkers, and we built a list of those that
+ // care about region changes, save it.
+ if (NewCO.get())
+ CO_Ref = NewCO.take();
+
+ return state;
+}
+
void GRExprEngine::ProcessEndWorklist(bool hasWorkRemaining) {
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 221406e..16aefbf 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -231,7 +231,8 @@
const MemRegion * const *End,
const Expr *E, unsigned Count,
InvalidatedSymbols *IS,
- bool invalidateGlobals);
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions);
public: // Made public for helper classes.
@@ -572,14 +573,16 @@
const Expr *Ex;
unsigned Count;
StoreManager::InvalidatedSymbols *IS;
+ StoreManager::InvalidatedRegions *Regions;
public:
InvalidateRegionsWorker(RegionStoreManager &rm,
GRStateManager &stateMgr,
RegionBindings b,
const Expr *ex, unsigned count,
- StoreManager::InvalidatedSymbols *is)
+ StoreManager::InvalidatedSymbols *is,
+ StoreManager::InvalidatedRegions *r)
: ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b),
- Ex(ex), Count(count), IS(is) {}
+ Ex(ex), Count(count), IS(is), Regions(r) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
void VisitBaseRegion(const MemRegion *baseR);
@@ -650,6 +653,10 @@
return;
}
+ // Otherwise, we have a normal data region. Record that we touched the region.
+ if (Regions)
+ Regions->push_back(baseR);
+
if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
@@ -700,10 +707,11 @@
const MemRegion * const *E,
const Expr *Ex, unsigned Count,
InvalidatedSymbols *IS,
- bool invalidateGlobals) {
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions) {
InvalidateRegionsWorker W(*this, StateMgr,
RegionStoreManager::GetRegionBindings(store),
- Ex, Count, IS);
+ Ex, Count, IS, Regions);
// Scan the bindings and generate the clusters.
W.GenerateClusters(invalidateGlobals);
@@ -726,6 +734,11 @@
/* symbol type, doesn't matter */ Ctx.IntTy,
Count);
B = Add(B, BindingKey::Make(GS, BindingKey::Default), V);
+
+ // Even if there are no bindings in the global scope, we still need to
+ // record that we touched it.
+ if (Regions)
+ Regions->push_back(GS);
}
return B.getRoot();