const ProgramPoint Location;
const ProgramState *ST;
const unsigned size;
- // TODO: Use global context.
- NodeBuilderContext Ctx;
NodeBuilder &NB;
public:
bool *respondsToCallback;
Location(loc),
ST(st),
size(Dst.size()),
- Ctx(builder.C.Eng, builder.getBlock(), pred),
NB(builder),
respondsToCallback(respondsToCB) {
assert(!(ST && ST != Pred->getState()));
}
/// Enqueue the results of the node builder onto the work list.
- void enqueue(NodeBuilder &NB);
+ void enqueue(ExplodedNodeSet &NB);
};
struct NodeBuilderContext {
protected:
friend class StmtNodeBuilder;
- ExplodedNode *BuilderPred;
-
-// TODO: Context should become protected after refactoring is done.
-public:
const NodeBuilderContext &C;
-protected:
/// Specifies if the builder results have been finalized. For example, if it
/// is set to false, autotransitions are yet to be generated.
/// \brief The frontier set - a set of nodes which need to be propagated after
/// the builder dies.
- typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
- DeferredTy Deferred;
+ ExplodedNodeSet &Frontier;
BlockCounter getBlockCounter() const { return C.Eng.WList->getBlockCounter();}
virtual bool checkResults() {
if (!Finalized)
return false;
- for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
- if ((*I)->isSink())
- return false;
return true;
}
bool MarkAsSink = false);
public:
- NodeBuilder(NodeBuilderContext &Ctx, bool F = true)
- : C(Ctx), Finalized(F), HasGeneratedNodes(false) {
- Deferred.insert(C.ContextPred);
+ NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ Frontier.insert(SrcNode);
}
- /// Create a new builder using the parent builder's context.
- NodeBuilder(const NodeBuilder &ParentBldr, bool F = true)
- : C(ParentBldr.C), Finalized(F), HasGeneratedNodes(false) {
- Deferred.insert(C.ContextPred);
+ NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ Frontier.insert(SrcSet);
}
virtual ~NodeBuilder() {}
return HasGeneratedNodes;
}
- typedef DeferredTy::iterator iterator;
+ const ExplodedNodeSet &getResults() {
+ finalizeResults();
+ assert(checkResults());
+ return Frontier;
+ }
+
+ typedef ExplodedNodeSet::iterator iterator;
/// \brief Iterators through the results frontier.
- inline iterator results_begin() {
+ inline iterator begin() {
finalizeResults();
assert(checkResults());
- return Deferred.begin();
+ return Frontier.begin();
}
- inline iterator results_end() {
+ inline iterator end() {
finalizeResults();
- return Deferred.end();
+ return Frontier.end();
}
/// \brief Return the CFGBlock associated with this builder.
const CFGBlock *getBlock() const { return C.Block; }
+ const NodeBuilderContext &getContext() { return C; }
+
/// \brief Returns the number of times the current basic block has been
/// visited on the exploded graph path.
unsigned getCurrentBlockCount() const {
void GenerateAutoTransition(ExplodedNode *N);
public:
- StmtNodeBuilder(ExplodedNode *N, unsigned idx, NodeBuilderContext &Ctx);
+ StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ unsigned idx, const NodeBuilderContext &Ctx)
+ : NodeBuilder(SrcNode, DstSet, Ctx), Idx(idx),
+ PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
+ PointKind(ProgramPoint::PostStmtKind), Tag(0) {}
~StmtNodeBuilder();
void importNodesFromBuilder(const NodeBuilder &NB) {
ExplodedNode *NBPred = const_cast<ExplodedNode*>(NB.C.ContextPred);
if (NB.hasGeneratedNodes()) {
- Deferred.erase(NBPred);
- Deferred.insert(NB.Deferred.begin(), NB.Deferred.end());
+ Frontier.erase(NBPred);
+ Frontier.insert(NB.Frontier);
}
}
};
bool InFeasibleFalse;
public:
- BranchNodeBuilder(NodeBuilderContext &C,
+ BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
- : NodeBuilder(C), DstT(dstT), DstF(dstF),
+ : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
- /// Create a new builder using the parent builder's context.
- BranchNodeBuilder(BranchNodeBuilder &ParentBldr)
- : NodeBuilder(ParentBldr), DstT(ParentBldr.DstT),
- DstF(ParentBldr.DstF),
+ BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
+ const CFGBlock *dstT, const CFGBlock *dstF)
+ : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
ExplodedNode *generateNode(const ProgramState *State, bool branch,
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
+ bool erase(ExplodedNode *N) { return Impl.erase(N); }
void clear() { Impl.clear(); }
void insert(const ExplodedNodeSet &S) {
BugReporter& getBugReporter() { return BR; }
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
+ const NodeBuilderContext &getBuilderContext() {
+ assert(Builder);
+ return Builder->getContext();
+ }
bool isObjCGCEnabled() { return ObjCGCEnabled; }
void processBranch(const Stmt *Condition, const Stmt *Term,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF);
virtual void processBranch(const Stmt *Condition, const Stmt *Term,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) = 0;
CheckerContext::~CheckerContext() {
// Copy the results into the Dst set.
- for (NodeBuilder::iterator I = NB.results_begin(),
- E = NB.results_end(); I != E; ++I) {
+ for (NodeBuilder::iterator I = NB.begin(),
+ E = NB.end(); I != E; ++I) {
Dst.Add(*I);
}
}
// Process the entrance of the block.
if (CFGElement E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
- StmtNodeBuilder Builder(Pred, 0, Ctx);
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder Builder(Pred, Dst, 0, Ctx);
SubEng.processCFGElement(E, Builder, Pred);
}
else
const CFGBlock * B, ExplodedNode *Pred) {
assert(B->succ_size() == 2);
NodeBuilderContext Ctx(*this, B, Pred);
- SubEng.processBranch(Cond, Term, Ctx, Pred,
+ ExplodedNodeSet Dst;
+ SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
*(B->succ_begin()), *(B->succ_begin()+1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
}
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
HandleBlockExit(B, Pred);
else {
NodeBuilderContext Ctx(*this, B, Pred);
- StmtNodeBuilder Builder(Pred, StmtIdx, Ctx);
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder Builder(Pred, Dst, StmtIdx, Ctx);
SubEng.processCFGElement((*B)[StmtIdx], Builder, Pred);
}
}
if (IsNew) WList->enqueue(Node);
}
-void CoreEngine::enqueue(NodeBuilder &NB) {
- for (NodeBuilder::iterator I = NB.results_begin(),
- E = NB.results_end(); I != E; ++I) {
+void CoreEngine::enqueue(ExplodedNodeSet &S) {
+ for (ExplodedNodeSet::iterator I = S.begin(),
+ E = S.end(); I != E; ++I) {
WList->enqueue(*I);
}
}
bool IsNew;
ExplodedNode *N = C.Eng.G->getNode(Loc, State, &IsNew);
N->addPredecessor(FromN, *C.Eng.G);
- Deferred.erase(FromN);
+ Frontier.erase(FromN);
if (MarkAsSink)
N->markAsSink();
-
- if (IsNew && !N->isSink())
- Deferred.insert(N);
+
+ if (IsNew)
+ Frontier.Add(N);
return (IsNew ? N : 0);
}
-
-StmtNodeBuilder::StmtNodeBuilder(ExplodedNode *N, unsigned idx,
- NodeBuilderContext &Ctx)
- : NodeBuilder(Ctx), Idx(idx),
- PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
- PointKind(ProgramPoint::PostStmtKind), Tag(0) {
- Deferred.insert(N);
-}
-
StmtNodeBuilder::~StmtNodeBuilder() {
- for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
+ for (iterator I=Frontier.begin(), E=Frontier.end(); I!=E; ++I)
if (!(*I)->isSink())
GenerateAutoTransition(*I);
}
C.Eng.WList->enqueue(Succ, C.Block, Idx+1);
}
-ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &Dst,
+ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &DstSet,
const Stmt *S,
ExplodedNode *Pred,
const ProgramState *St,
ProgramPoint::Kind K) {
ExplodedNode *N = generateNode(S, St, Pred, K, 0, BuildSinks);
if (N && !BuildSinks){
- Dst.Add(N);
+ DstSet.Add(N);
}
return N;
}
void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
NodeBuilderContext& BldCtx,
ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
-
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
- BranchNodeBuilder NullCondBldr(BldCtx, DstT, DstF);
+ BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
NullCondBldr.markInfeasible(false);
NullCondBldr.generateNode(Pred->getState(), true, Pred);
- Engine.enqueue(NullCondBldr);
return;
}
Condition->getLocStart(),
"Error evaluating branch");
- NodeBuilder CheckerBldr(BldCtx);
+ ExplodedNodeSet TmpCheckersOut;
+ NodeBuilder CheckerBldr(Pred, TmpCheckersOut, BldCtx);
getCheckerManager().runCheckersForBranchCondition(Condition, CheckerBldr,
Pred, *this);
- for (NodeBuilder::iterator I = CheckerBldr.results_begin(),
- E = CheckerBldr.results_end(); E != I; ++I) {
+ BranchNodeBuilder builder(CheckerBldr.getResults(), Dst, BldCtx, DstT, DstF);
+ for (NodeBuilder::iterator I = CheckerBldr.begin(),
+ E = CheckerBldr.end(); E != I; ++I) {
ExplodedNode *PredI = *I;
if (PredI->isSink())
continue;
- BranchNodeBuilder builder(BldCtx, DstT, DstF);
const ProgramState *PrevState = Pred->getState();
SVal X = PrevState->getSVal(Condition);
if (X.isUnknownOrUndef()) {
builder.generateNode(MarkBranch(PrevState, Term, true), true, PredI);
builder.generateNode(MarkBranch(PrevState, Term, false), false, PredI);
- // Enqueue the results into the work list.
- Engine.enqueue(builder);
continue;
}
else
builder.markInfeasible(false);
}
-
- // Enqueue the results into the work list.
- Engine.enqueue(builder);
}
}