Refactor DereferenceChecker to use only the new Checker API instead of
the old builder API. This percolated a bunch of changes up to the
Checker class (where CheckLocation has been renamed VisitLocation) and
GRExprEngine. ProgramPoint now has the notion of a "LocationCheck"
point (with PreLoad and PreStore respectively), and a bunch of the old
ProgramPoints that are no longer used have been removed.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86798 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 528a469..c7b8036 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -1190,68 +1190,87 @@
assert(Builder && "GRStmtNodeBuilder must be defined.");
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(StoreE, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, StoreE, Pred, state, location, tag, false);
- if (!Pred)
+ if (Tmp.empty())
return;
- assert (!location.isUndef());
- state = GetState(Pred);
+ assert(!location.isUndef());
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
+ ProgramPoint::PostStoreKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
+
// Proceed with the store.
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->PointKind = ProgramPoint::PostStoreKind;
- Builder->Tag = tag;
- EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
}
-void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag) {
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(Ex, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
- if (!Pred)
+ if (Tmp.empty())
return;
-
- state = GetState(Pred);
+
+ assert(!location.isUndef());
+
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
// Proceed with the load.
- ProgramPoint::Kind K = ProgramPoint::PostLoadKind;
-
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()),
- K, tag);
- }
- else {
- SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ state = GetState(*NI);
+ if (location.isUnknown()) {
+ // This is important. We must nuke the old binding.
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+ ProgramPoint::PostLoadKind, tag);
+ }
+ else {
+ SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
+ tag);
+ }
}
}
-ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag) {
+void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
+ ExplodedNode* Pred,
+ const GRState* state, SVal location,
+ const void *tag, bool isLoad) {
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->Tag = tag;
-
- if (location.isUnknown() || Checkers.empty())
- return Pred;
-
-
- for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
- {
- Pred = I->second->CheckLocation(Ex, Pred, state, location, *this);
- if (!Pred)
- break;
+ if (location.isUnknown() || Checkers.empty()) {
+ Dst.Add(Pred);
+ return;
}
- return Pred;
-
+ ExplodedNodeSet Src, Tmp;
+ Src.Add(Pred);
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ : (PrevSet == &Tmp) ? &Src : &Tmp;
+
+ CurrSet->clear();
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state,
+ location, tag, isLoad);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
+ }
+
// FIXME: Temporarily disable out-of-bounds checking until we make
// the logic reflect recent changes to CastRegion and friends.
#if 0
@@ -1746,46 +1765,47 @@
ExplodedNode* Pred, ExplodedNodeSet& Dst,
SVal ElementV) {
-
-
- // Get the current state. Use 'EvalLocation' to determine if it is a null
- // pointer, etc.
+ // Check if the location we are writing back to is a null pointer.
Stmt* elem = S->getElement();
-
- Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV);
- if (!Pred)
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
+
+ if (Tmp.empty())
return;
+
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ Pred = *NI;
+ const GRState *state = GetState(Pred);
- const GRState *state = GetState(Pred);
+ // Handle the case where the container still has elements.
+ SVal TrueV = ValMgr.makeTruthVal(1);
+ const GRState *hasElems = state->BindExpr(S, TrueV);
- // Handle the case where the container still has elements.
- SVal TrueV = ValMgr.makeTruthVal(1);
- const GRState *hasElems = state->BindExpr(S, TrueV);
+ // Handle the case where the container has no elements.
+ SVal FalseV = ValMgr.makeTruthVal(0);
+ const GRState *noElems = state->BindExpr(S, FalseV);
- // Handle the case where the container has no elements.
- SVal FalseV = ValMgr.makeTruthVal(0);
- const GRState *noElems = state->BindExpr(S, FalseV);
+ if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
+ if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
+ // FIXME: The proper thing to do is to really iterate over the
+ // container. We will do this with dispatch logic to the store.
+ // For now, just 'conjure' up a symbolic value.
+ QualType T = R->getValueType(getContext());
+ assert(Loc::IsLocType(T));
+ unsigned Count = Builder->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ SVal V = ValMgr.makeLoc(Sym);
+ hasElems = hasElems->bindLoc(ElementV, V);
- if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
- if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
- // FIXME: The proper thing to do is to really iterate over the
- // container. We will do this with dispatch logic to the store.
- // For now, just 'conjure' up a symbolic value.
- QualType T = R->getValueType(getContext());
- assert (Loc::IsLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
- SVal V = ValMgr.makeLoc(Sym);
- hasElems = hasElems->bindLoc(ElementV, V);
+ // Bind the location to 'nil' on the false branch.
+ SVal nilV = ValMgr.makeIntVal(0, T);
+ noElems = noElems->bindLoc(ElementV, nilV);
+ }
- // Bind the location to 'nil' on the false branch.
- SVal nilV = ValMgr.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
- }
-
- // Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
+ // Create the new nodes.
+ MakeNode(Dst, S, Pred, hasElems);
+ MakeNode(Dst, S, Pred, noElems);
+ }
}
//===----------------------------------------------------------------------===//
@@ -2920,10 +2940,6 @@
Out << "\\lPostStore\\l";
else if (isa<PostLValue>(Loc))
Out << "\\lPostLValue\\l";
- else if (isa<PostLocationChecksSucceed>(Loc))
- Out << "\\lPostLocationChecksSucceed\\l";
- else if (isa<PostNullCheckFailed>(Loc))
- Out << "\\lPostNullCheckFailed\\l";
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";