From: Anna Zaks Date: Tue, 25 Oct 2011 19:56:48 +0000 (+0000) Subject: [analyze] Convert EndOfPath callback to use CheckerContext X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=af498a28797c075c48d7e943df5f5a8e78ed8eb0;p=clang [analyze] Convert EndOfPath callback to use CheckerContext Get rid of the EndOfPathBuilder completely. Use the generic NodeBuilder to generate nodes. Enqueue the end of path frontier explicitly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142943 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 2e270000c7..181080a213 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -199,9 +199,9 @@ public: class EndPath { template - static void _checkEndPath(void *checker, EndOfFunctionNodeBuilder &B, - ExprEngine &Eng) { - ((const CHECKER *)checker)->checkEndPath(B, Eng); + static void _checkEndPath(void *checker, + CheckerContext &C) { + ((const CHECKER *)checker)->checkEndPath(C); } public: diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 6da75a948a..e74bd8b826 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -39,8 +39,8 @@ namespace ento { class ExplodedNodeSet; class ExplodedGraph; class ProgramState; - class EndOfFunctionNodeBuilder; class NodeBuilder; + struct NodeBuilderContext; class MemRegion; class SymbolReaper; @@ -230,7 +230,9 @@ public: ExprEngine &Eng); /// \brief Run checkers for end of path. - void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng); + void runCheckersForEndPath(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, + ExprEngine &Eng); /// \brief Run checkers for branch condition. void runCheckersForBranchCondition(const Stmt *condition, @@ -334,7 +336,7 @@ public: typedef CheckerFn CheckEndAnalysisFunc; - typedef CheckerFn + typedef CheckerFn CheckEndPathFunc; typedef CheckerFnisSink()); } + : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); } /// \brief Return the CFGBlock associated with this builder. const CFGBlock *getBlock() const { return Block; } @@ -182,10 +182,9 @@ struct NodeBuilderContext { /// visited on the exploded graph path. unsigned getCurrentBlockCount() const { return Eng.WList->getBlockCounter().getNumVisited( - ContextPred->getLocationContext()->getCurrentStackFrame(), + Pred->getLocationContext()->getCurrentStackFrame(), Block->getBlockID()); } - }; /// \class NodeBuilder @@ -289,15 +288,6 @@ public: void addNodes(ExplodedNode *N) { Frontier.Add(N); } }; -class CommonNodeBuilder { -protected: - ExplodedNode *Pred; - CoreEngine &Eng; - - CommonNodeBuilder(CoreEngine* E, ExplodedNode *P) : Pred(P), Eng(*E) {} - BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); } -}; - /// \class StmtNodeBuilder /// \brief This builder class is useful for generating nodes that resulted from /// visiting a statement. The main difference from it's parent NodeBuilder is @@ -523,47 +513,6 @@ public: const PP_T &getProgramPoint() const { return cast(pp); } }; -class EndOfFunctionNodeBuilder : public CommonNodeBuilder { - const CFGBlock &B; - const ProgramPointTag *Tag; - -public: - bool hasGeneratedNode; - -public: - EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e, - const ProgramPointTag *tag = 0) - : CommonNodeBuilder(e, N), B(*b), Tag(tag), hasGeneratedNode(false) {} - - ~EndOfFunctionNodeBuilder(); - - EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) { - return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag); - } - - WorkList &getWorkList() { return *Eng.WList; } - - ExplodedNode *getPredecessor() const { return Pred; } - - unsigned getCurrentBlockCount() const { - return getBlockCounter().getNumVisited( - Pred->getLocationContext()->getCurrentStackFrame(), - B.getBlockID()); - } - - ExplodedNode *generateNode(const ProgramState *State, - ExplodedNode *P = 0, - const ProgramPointTag *tag = 0); - - void GenerateCallExitNode(const ProgramState *state); - - const CFGBlock *getBlock() const { return &B; } - - const ProgramState *getState() const { - return getPredecessor()->getState(); - } -}; - class CallEnterNodeBuilder { CoreEngine &Eng; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 0fb8dad650..325d824090 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -124,6 +124,8 @@ public: const Stmt *getStmt() const; void GenerateAutoTransition(ExplodedNode *N); + void enqueueEndOfPath(ExplodedNodeSet &S); + void GenerateCallExitNode(ExplodedNode *N); /// ViewGraph - Visualize the ExplodedGraph created by executing the /// simulation. @@ -181,7 +183,7 @@ public: /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. - void processEndOfFunction(EndOfFunctionNodeBuilder& builder); + void processEndOfFunction(NodeBuilderContext& BC); /// Generate the entry node of the callee. void processCallEnter(CallEnterNodeBuilder &builder); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index 8989a723e5..c35e6cca41 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -82,7 +82,7 @@ public: /// Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. - virtual void processEndOfFunction(EndOfFunctionNodeBuilder& builder) = 0; + virtual void processEndOfFunction(NodeBuilderContext& BC) = 0; // Generate the entry node of the callee. virtual void processCallEnter(CallEnterNodeBuilder &builder) = 0; diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index 2607db80ba..e975dd55a8 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -58,7 +58,7 @@ public: void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; void checkPostStmt(const CallExpr *S, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; - void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + void checkEndPath(CheckerContext &Ctx) const; private: typedef std::pair AllocationPair; @@ -557,9 +557,8 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, } // TODO: Remove this after we ensure that checkDeadSymbols are always called. -void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B, - ExprEngine &Eng) const { - const ProgramState *state = B.getState(); +void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &Ctx) const { + const ProgramState *state = Ctx.getState(); AllocatedSetTy AS = state->get(); if (AS.isEmpty()) return; @@ -575,7 +574,7 @@ void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B, // allocation, do not report. if (state->getSymVal(I.getKey()) || definitelyReturnedError(I->second.Region, state, - Eng.getSValBuilder())) { + Ctx.getSValBuilder())) { continue; } Errors.push_back(std::make_pair(I->first, &I->second)); @@ -585,15 +584,14 @@ void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B, if (!Changed) return; - ExplodedNode *N = B.generateNode(state); + ExplodedNode *N = Ctx.generateNode(state); if (!N) return; // Generate the error reports. for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { - Eng.getBugReporter().EmitReport( - generateAllocatedDataNotReleasedReport(*I, N)); + Ctx.EmitReport(generateAllocatedDataNotReleasedReport(*I, N)); } } diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 5631802b7c..a04f02493d 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -78,7 +78,7 @@ public: bool evalCall(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; - void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + void checkEndPath(CheckerContext &C) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; const ProgramState *evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const; @@ -604,21 +604,20 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, } } -void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B, - ExprEngine &Eng) const { - const ProgramState *state = B.getState(); +void MallocChecker::checkEndPath(CheckerContext &Ctx) const { + const ProgramState *state = Ctx.getState(); RegionStateTy M = state->get(); for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { RefState RS = I->second; if (RS.isAllocated()) { - ExplodedNode *N = B.generateNode(state); + ExplodedNode *N = Ctx.generateNode(state); if (N) { if (!BT_Leak) BT_Leak.reset(new BuiltinBug("Memory leak", "Allocated memory never released. Potential memory leak.")); BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); - Eng.getBugReporter().EmitReport(R); + Ctx.EmitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index fcf0af9ba4..c7d108b2f7 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -47,24 +47,13 @@ class GenericNodeBuilderRefCount { EndOfFunctionNodeBuilder *ENB; public: GenericNodeBuilderRefCount(CheckerContext &c, - const ProgramPointTag *t) + const ProgramPointTag *t = 0) : C(&c), tag(t), ENB(0) {} - GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb) - : C(0), tag(0), ENB(&enb) {} - ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred, bool MarkAsSink = false) { - if (C) { - return C->generateNode(state, Pred, tag, false, MarkAsSink); - } - - assert(ENB); - ExplodedNode *N = ENB->generateNode(state, Pred); - if (MarkAsSink) - N->markAsSink(); - - return N; + assert(C); + return C->generateNode(state, Pred, tag, false, MarkAsSink); } }; } // end anonymous namespace @@ -2445,7 +2434,7 @@ public: SymbolRef Sym, const ProgramState *state) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; - void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const; + void checkEndPath(CheckerContext &C) const; const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind &hasErr, @@ -3439,12 +3428,12 @@ RetainCountChecker::processLeaks(const ProgramState *state, return N; } -void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder, - ExprEngine &Eng) const { - const ProgramState *state = Builder.getState(); - GenericNodeBuilderRefCount Bd(Builder); +void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const { + const ProgramState *state = Ctx.getState(); + GenericNodeBuilderRefCount Bd(Ctx); RefBindings B = state->get(); - ExplodedNode *Pred = Builder.getPredecessor(); + ExplodedNode *Pred = Ctx.getPredecessor(); + ExprEngine &Eng = Ctx.getEngine(); for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng, diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 91c4b96d69..fed9c20d6e 100644 --- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -31,7 +31,7 @@ class StackAddrEscapeChecker : public Checker< check::PreStmt, public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; - void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + void checkEndPath(CheckerContext &Ctx) const; private: void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const; @@ -136,22 +136,22 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, } } -void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, - ExprEngine &Eng) const { - - const ProgramState *state = B.getState(); +void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { + const ProgramState *state = Ctx.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. class CallBack : public StoreManager::BindingsHandler { private: - ExprEngine &Eng; + CheckerContext &Ctx; const StackFrameContext *CurSFC; public: SmallVector, 10> V; - CallBack(ExprEngine &Eng, const LocationContext *LCtx) - : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {} + CallBack(CheckerContext &CC) : + Ctx(CC), + CurSFC(CC.getPredecessor()->getLocationContext()->getCurrentStackFrame()) + {} bool HandleBinding(StoreManager &SMgr, Store store, const MemRegion *region, SVal val) { @@ -165,7 +165,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, // Under automated retain release, it is okay to assign a block // directly to a global variable. - if (Eng.getContext().getLangOptions().ObjCAutoRefCount && + if (Ctx.getASTContext().getLangOptions().ObjCAutoRefCount && isa(vR)) return true; @@ -181,14 +181,14 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, } }; - CallBack cb(Eng, B.getPredecessor()->getLocationContext()); + CallBack cb(Ctx); state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); if (cb.V.empty()) return; // Generate an error node. - ExplodedNode *N = B.generateNode(state); + ExplodedNode *N = Ctx.generateNode(state); if (!N) return; @@ -204,7 +204,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, llvm::SmallString<512> buf; llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, cb.V[i].second, - Eng.getContext().getSourceManager()); + Ctx.getSourceManager()); os << " is still referred to by the global variable '"; const VarRegion *VR = cast(cb.V[i].first->getBaseRegion()); os << *VR->getDecl() @@ -213,7 +213,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, if (range.isValid()) report->addRange(range); - Eng.getBugReporter().EmitReport(report); + Ctx.EmitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 1d14e9e15e..8010e8dbac 100644 --- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -75,7 +75,7 @@ public: bool evalCall(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; - void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + void checkEndPath(CheckerContext &Ctx) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; private: @@ -418,23 +418,22 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, } } -void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B, - ExprEngine &Eng) const { - const ProgramState *state = B.getState(); +void StreamChecker::checkEndPath(CheckerContext &Ctx) const { + const ProgramState *state = Ctx.getState(); typedef llvm::ImmutableMap SymMap; SymMap M = state->get(); for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { StreamState SS = I->second; if (SS.isOpened()) { - ExplodedNode *N = B.generateNode(state); + ExplodedNode *N = Ctx.generateNode(state); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); - Eng.getBugReporter().EmitReport(R); + Ctx.EmitReport(R); } } } diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index b24f9a0b3c..67fe4d6ca2 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -298,12 +298,25 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, } /// \brief Run checkers for end of path. -void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B, +// Note, We do not chain the checker output (like in expandGraphWithCheckers) +// for this callback since end of path nodes are expected to be final. +void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, ExprEngine &Eng) { + ExplodedNode *Pred = BC.Pred; + + // We define the builder outside of the loop bacause if at least one checkers + // creates a sucsessor for Pred, we do not need to generate an + // autotransition for it. + NodeBuilder Bldr(Pred, Dst, BC); for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) { - CheckEndPathFunc fn = EndPathCheckers[i]; - EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker); - fn(specialB, Eng); + CheckEndPathFunc checkFn = EndPathCheckers[i]; + + const ProgramPoint &L = BlockEntrance(BC.Block, + Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L, 0); + checkFn(C); } } diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index 6a14815d5d..6b8c7df224 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -269,8 +269,8 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { && "EXIT block cannot contain Stmts."); // Process the final state transition. - EndOfFunctionNodeBuilder Builder(Blk, Pred, this); - SubEng.processEndOfFunction(Builder); + NodeBuilderContext BuilderCtx(*this, Blk, Pred); + SubEng.processEndOfFunction(BuilderCtx); // This path is done. Don't enqueue any more nodes. return; @@ -597,57 +597,6 @@ SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St, return NULL; } -EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() { - // Auto-generate an EOP node if one has not been generated. - if (!hasGeneratedNode) { - // If we are in an inlined call, generate CallExit node. - if (Pred->getLocationContext()->getParent()) - GenerateCallExitNode(Pred->State); - else - generateNode(Pred->State); - } -} - -ExplodedNode* -EndOfFunctionNodeBuilder::generateNode(const ProgramState *State, - ExplodedNode *P, - const ProgramPointTag *tag) { - hasGeneratedNode = true; - bool IsNew; - - ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B, - Pred->getLocationContext(), tag ? tag : Tag), - State, &IsNew); - - Node->addPredecessor(P ? P : Pred, *Eng.G); - - if (IsNew) { - Eng.G->addEndOfPath(Node); - return Node; - } - - return NULL; -} - -void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) { - hasGeneratedNode = true; - // Create a CallExit node and enqueue it. - const StackFrameContext *LocCtx - = cast(Pred->getLocationContext()); - const Stmt *CE = LocCtx->getCallSite(); - - // Use the the callee location context. - CallExit Loc(CE, LocCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(Pred, *Eng.G); - - if (isNew) - Eng.WList->enqueue(Node); -} - - void CallEnterNodeBuilder::generateNode(const ProgramState *state) { // Check if the callee is in the same translation unit. if (CalleeCtx->getTranslationUnit() != diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 13550c793d..3e5a31cda0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1153,11 +1153,42 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { builder.generateNode(I, state); } +// TODO: The next two functions should be moved into CoreEngine. +void ExprEngine::GenerateCallExitNode(ExplodedNode *N) { + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast(N->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // Use the the callee location context. + CallExit Loc(CE, LocCtx); + + bool isNew; + ExplodedNode *Node = Engine.G->getNode(Loc, N->getState(), &isNew); + Node->addPredecessor(N, *Engine.G); + + if (isNew) + Engine.WList->enqueue(Node); +} + +void ExprEngine::enqueueEndOfPath(ExplodedNodeSet &S) { + for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I) { + ExplodedNode *N = *I; + // If we are in an inlined call, generate CallExit node. + if (N->getLocationContext()->getParent()) + GenerateCallExitNode(N); + else + Engine.G->addEndOfPath(N); + } +} + /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. -void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) { - StateMgr.EndPath(builder.getState()); - getCheckerManager().runCheckersForEndPath(builder, *this); +void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) { + StateMgr.EndPath(BC.Pred->getState()); + ExplodedNodeSet Dst; + getCheckerManager().runCheckersForEndPath(BC, Dst, *this); + enqueueEndOfPath(Dst); } /// ProcessSwitch - Called by CoreEngine. Used to generate successor