[analyzer] Use a temporary builder in CheckerContext.

First step toward removing the global Stmt builder. Added several transitional methods (like takeNodes/addNodes).
+ Stop early if the set of exploded nodes for the next iteration is empty.

llvm-svn: 142827
This commit is contained in:
Anna Zaks 2011-10-24 18:25:58 +00:00
parent 7fec527d16
commit 0bb9d1b917
6 changed files with 68 additions and 37 deletions

View File

@ -23,29 +23,24 @@ namespace clang {
namespace ento {
class CheckerContext {
ExplodedNodeSet &Dst;
ExprEngine &Eng;
ExplodedNode *Pred;
const ProgramPoint Location;
const ProgramState *ST;
const unsigned size;
NodeBuilder &NB;
public:
bool *respondsToCallback;
public:
CheckerContext(ExplodedNodeSet &dst,
NodeBuilder &builder,
CheckerContext(NodeBuilder &builder,
ExprEngine &eng,
ExplodedNode *pred,
const ProgramPoint &loc,
bool *respondsToCB = 0,
const ProgramState *st = 0)
: Dst(dst),
Eng(eng),
: Eng(eng),
Pred(pred),
Location(loc),
ST(st),
size(Dst.size()),
NB(builder),
respondsToCallback(respondsToCB) {
assert(!(ST && ST != Pred->getState()));
@ -153,7 +148,6 @@ private:
bool markAsSink,
ExplodedNode *pred = 0,
const ProgramPointTag *tag = 0) {
ExplodedNode *node = NB.generateNode(tag ? Location.withTag(tag) : Location,
state,
pred ? pred : Pred, markAsSink);

View File

@ -202,6 +202,14 @@ protected:
return true;
}
bool haveNoSinksInFrontier() {
for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) {
if ((*I)->isSink())
return false;
}
return true;
}
/// Allow subclasses to finalize results before result_begin() is executed.
virtual void finalizeResults() {}
@ -214,13 +222,19 @@ public:
NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, bool F = true)
: C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
Frontier.insert(SrcNode);
assert(DstSet.empty());
Frontier.Add(SrcNode);
}
NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, bool F = true)
: C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
assert(DstSet.empty());
//assert(!SrcSet.empty());
Frontier.insert(SrcSet);
assert(haveNoSinksInFrontier());
}
virtual ~NodeBuilder() {}
@ -365,13 +379,23 @@ public:
return N;
}
void importNodesFromBuilder(const NodeBuilder &NB) {
ExplodedNode *NBPred = const_cast<ExplodedNode*>(NB.C.ContextPred);
if (NB.hasGeneratedNodes()) {
Frontier.erase(NBPred);
Frontier.insert(NB.Frontier);
}
void takeNodes(const ExplodedNodeSet &S) {
for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
Frontier.erase(*I);
}
void takeNodes(ExplodedNode *N) {
Frontier.erase(N);
}
void addNodes(const ExplodedNodeSet &S) {
Frontier.insert(S);
}
void addNodes(ExplodedNode *N) {
Frontier.Add(N);
}
};
class BranchNodeBuilder: public NodeBuilder {

View File

@ -16,10 +16,4 @@
using namespace clang;
using namespace ento;
CheckerContext::~CheckerContext() {
// Copy the results into the Dst set.
for (NodeBuilder::iterator I = NB.begin(),
E = NB.end(); I != E; ++I) {
Dst.Add(*I);
}
}
CheckerContext::~CheckerContext() {}

View File

@ -93,6 +93,9 @@ template <typename CHECK_CTX>
static void expandGraphWithCheckers(CHECK_CTX checkCtx,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src) {
const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
if (Src.empty())
return;
typename CHECK_CTX::CheckersTy::const_iterator
I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
@ -113,9 +116,18 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx,
CurrSet->clear();
}
NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
checkCtx.Eng.getBuilder().takeNodes(*PrevSet);
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
checkCtx.runChecker(*I, *CurrSet, *NI);
NI != NE; ++NI) {
checkCtx.runChecker(*I, B, *NI);
}
// If all the produced transitions are sinks, stop.
if (CurrSet->empty())
return;
checkCtx.Eng.getBuilder().addNodes(*CurrSet);
// Update which NodeSet is the current one.
PrevSet = CurrSet;
@ -138,13 +150,13 @@ namespace {
: IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckStmtFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
NodeBuilder &Bldr, ExplodedNode *Pred) {
// FIXME: Remove respondsToCallback from CheckerContext;
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(Bldr, Eng, Pred, L, 0);
checkFn(S, C);
}
@ -178,12 +190,12 @@ namespace {
: IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
K, Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(Bldr, Eng, Pred, L, 0);
checkFn(Msg, C);
}
@ -220,12 +232,12 @@ namespace {
: Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckLocationFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind :
ProgramPoint::PreStoreKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(Bldr, Eng, Pred, L, 0);
checkFn(Loc, IsLoad, S, C);
}
@ -258,11 +270,11 @@ namespace {
: Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckBindFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = ProgramPoint::PreStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(Bldr, Eng, Pred, L, 0);
checkFn(Loc, Val, S, C);
}
@ -329,11 +341,11 @@ namespace {
: Checkers(checkers), SR(sr), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(Bldr, Eng, Pred, L, 0);
checkFn(SR, C);
}
@ -438,11 +450,13 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
}
#endif
Eng.getBuilder().takeNodes(Pred);
ExplodedNodeSet checkDst;
NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
// Next, check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
ExplodedNodeSet checkDst;
ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
Pred->getLocationContext(), EI->Checker);
@ -450,7 +464,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
{ // CheckerContext generates transitions(populates checkDest) on
// destruction, so introduce the scope to make sure it gets properly
// populated.
CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
CheckerContext C(B, Eng, Pred, L, 0);
evaluated = (*EI)(CE, C);
}
assert(!(evaluated && anyEvaluated)
@ -458,6 +472,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
if (evaluated) {
anyEvaluated = true;
Dst.insert(checkDst);
Eng.getBuilder().addNodes(checkDst);
#ifdef NDEBUG
break; // on release don't check that no other checker also evals.
#endif
@ -466,6 +481,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
// If none of the checkers evaluated the call, ask ExprEngine to handle it.
if (!anyEvaluated) {
Eng.getBuilder().addNodes(Pred);
if (defaultEval)
defaultEval->expandGraph(Dst, Pred);
else

View File

@ -504,7 +504,7 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
if (MarkAsSink)
N->markAsSink();
if (IsNew)
if (IsNew && !MarkAsSink)
Frontier.Add(N);
return (IsNew ? N : 0);

View File

@ -964,6 +964,9 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
NodeBuilder CheckerBldr(Pred, TmpCheckersOut, BldCtx);
getCheckerManager().runCheckersForBranchCondition(Condition, CheckerBldr,
Pred, *this);
// We generated only sinks.
if (TmpCheckersOut.empty())
return;
BranchNodeBuilder builder(CheckerBldr.getResults(), Dst, BldCtx, DstT, DstF);
for (NodeBuilder::iterator I = CheckerBldr.begin(),