diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/CoreEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CoreEngine.cpp | 592 |
1 files changed, 227 insertions, 365 deletions
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index 5252198..eb986af 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "CoreEngine" + #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" @@ -20,9 +22,16 @@ #include "clang/AST/StmtCXX.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Statistic.h" + using namespace clang; using namespace ento; +STATISTIC(NumReachedMaxSteps, + "The # of times we reached the max number of steps."); +STATISTIC(NumPathsExplored, + "The # of paths explored by the analyzer."); + //===----------------------------------------------------------------------===// // Worklist classes for exploration of reachable states. //===----------------------------------------------------------------------===// @@ -152,7 +161,7 @@ WorkList* WorkList::makeBFSBlockDFSContents() { /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, - const ProgramState *InitState) { + ProgramStateRef InitState) { if (G->num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. @@ -165,6 +174,11 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); + // Mark the entry block as visited. + FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(), + L->getDecl(), + L->getCFG()->getNumBlockIDs()); + // Get the solitary successor. const CFGBlock *Succ = *(Entry->succ_begin()); @@ -187,8 +201,10 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, while (WList->hasWork()) { if (!UnlimitedSteps) { - if (Steps == 0) + if (Steps == 0) { + NumReachedMaxSteps++; break; + } --Steps; } @@ -200,67 +216,80 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, // Retrieve the node. ExplodedNode *Node = WU.getNode(); - // Dispatch on the location type. - switch (Node->getLocation().getKind()) { - case ProgramPoint::BlockEdgeKind: - HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockEntranceKind: - HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockExitKind: - assert (false && "BlockExit location never occur in forward analysis."); - break; + dispatchWorkItem(Node, Node->getLocation(), WU); + } + SubEng.processEndWorklist(hasWorkRemaining()); + return WList->hasWork(); +} - case ProgramPoint::CallEnterKind: - HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(), - WU.getIndex(), Node); - break; +void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, + const WorkListUnit& WU) { + // Dispatch on the location type. + switch (Loc.getKind()) { + case ProgramPoint::BlockEdgeKind: + HandleBlockEdge(cast<BlockEdge>(Loc), Pred); + break; + + case ProgramPoint::BlockEntranceKind: + HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred); + break; + + case ProgramPoint::BlockExitKind: + assert (false && "BlockExit location never occur in forward analysis."); + break; + + case ProgramPoint::CallEnterKind: { + CallEnter CEnter = cast<CallEnter>(Loc); + if (AnalyzedCallees) + if (const CallExpr* CE = + dyn_cast_or_null<CallExpr>(CEnter.getCallExpr())) + if (const Decl *CD = CE->getCalleeDecl()) + AnalyzedCallees->insert(CD); + SubEng.processCallEnter(CEnter, Pred); + break; + } - case ProgramPoint::CallExitKind: - HandleCallExit(cast<CallExit>(Node->getLocation()), Node); - break; + case ProgramPoint::CallExitKind: + SubEng.processCallExit(Pred); + break; - default: - assert(isa<PostStmt>(Node->getLocation()) || - isa<PostInitializer>(Node->getLocation())); - HandlePostStmt(WU.getBlock(), WU.getIndex(), Node); - break; + case ProgramPoint::EpsilonKind: { + assert(Pred->hasSinglePred() && + "Assume epsilon has exactly one predecessor by construction"); + ExplodedNode *PNode = Pred->getFirstPred(); + dispatchWorkItem(Pred, PNode->getLocation(), WU); + break; } + default: + assert(isa<PostStmt>(Loc) || + isa<PostInitializer>(Loc)); + HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred); + break; } - - SubEng.processEndWorklist(hasWorkRemaining()); - return WList->hasWork(); } -void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, +bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, - const ProgramState *InitState, + ProgramStateRef InitState, ExplodedNodeSet &Dst) { - ExecuteWorkList(L, Steps, InitState); - for (SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(), - E = G->EndNodes.end(); I != E; ++I) { + bool DidNotFinish = ExecuteWorkList(L, Steps, InitState); + for (ExplodedGraph::eop_iterator I = G->eop_begin(), + E = G->eop_end(); I != E; ++I) { Dst.Add(*I); } -} - -void CoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, - unsigned Index, ExplodedNode *Pred) { - CallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), - L.getCalleeContext(), Block, Index); - SubEng.processCallEnter(Builder); -} - -void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { - CallExitNodeBuilder Builder(*this, Pred); - SubEng.processCallExit(Builder); + return DidNotFinish; } void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { const CFGBlock *Blk = L.getDst(); + NodeBuilderContext BuilderCtx(*this, Blk, Pred); + + // Mark this block as visited. + const LocationContext *LC = Pred->getLocationContext(); + FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), + LC->getDecl(), + LC->getCFG()->getNumBlockIDs()); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { @@ -269,53 +298,42 @@ 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); + SubEng.processEndOfFunction(BuilderCtx); // This path is done. Don't enqueue any more nodes. return; } - // Call into the subengine to process entering the CFGBlock. + // Call into the SubEngine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); - GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE); - SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder); + NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); + SubEng.processCFGBlockEntrance(L, nodeBuilder); - if (dstNodes.empty()) { - if (!nodeBuilder.hasGeneratedNode) { - // Auto-generate a node and enqueue it to the worklist. - generateNode(BE, Pred->State, Pred); - } - } - else { - for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end(); - I != E; ++I) { - WList->enqueue(*I); - } + // Auto-generate a node. + if (!nodeBuilder.hasGeneratedNodes()) { + nodeBuilder.generateNode(Pred->State, Pred); } - for (SmallVectorImpl<ExplodedNode*>::const_iterator - I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end(); - I != E; ++I) { - blocksExhausted.push_back(std::make_pair(L, *I)); - } + // Enqueue nodes onto the worklist. + enqueue(dstNodes); } void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, ExplodedNode *Pred) { // Increment the block counter. + const LocationContext *LC = Pred->getLocationContext(); + unsigned BlockId = L.getBlock()->getBlockID(); BlockCounter Counter = WList->getBlockCounter(); - Counter = BCounterFactory.IncrementCount(Counter, - Pred->getLocationContext()->getCurrentStackFrame(), - L.getBlock()->getBlockID()); + Counter = BCounterFactory.IncrementCount(Counter, LC->getCurrentStackFrame(), + BlockId); WList->setBlockCounter(Counter); // Process the entrance of the block. if (CFGElement E = L.getFirstElement()) { - StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this); - SubEng.processCFGElement(E, Builder); + NodeBuilderContext Ctx(*this, L.getBlock(), Pred); + SubEng.processCFGElement(E, Pred, 0, &Ctx); } else HandleBlockExit(L.getBlock(), Pred); @@ -345,6 +363,19 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred); return; + case Stmt::CXXTryStmtClass: { + // Generate a node for each of the successors. + // Our logic for EH analysis can certainly be improved. + for (CFGBlock::const_succ_iterator it = B->succ_begin(), + et = B->succ_end(); it != et; ++it) { + if (const CFGBlock *succ = *it) { + generateNode(BlockEdge(B, succ, Pred->getLocationContext()), + Pred->State, Pred); + } + } + return; + } + case Stmt::DoStmtClass: HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred); return; @@ -417,31 +448,35 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock * B, ExplodedNode *Pred) { assert(B->succ_size() == 2); - BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), - Pred, this); - SubEng.processBranch(Cond, Term, Builder); + NodeBuilderContext Ctx(*this, B, 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, ExplodedNode *Pred) { - assert (!B->empty()); + assert(B); + assert(!B->empty()); if (StmtIdx == B->size()) HandleBlockExit(B, Pred); else { - StmtNodeBuilder Builder(B, StmtIdx, Pred, this); - SubEng.processCFGElement((*B)[StmtIdx], Builder); + NodeBuilderContext Ctx(*this, B, Pred); + SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx); } } /// generateNode - Utility method to generate nodes, hook up successors, /// and add nodes to the worklist. void CoreEngine::generateNode(const ProgramPoint &Loc, - const ProgramState *State, + ProgramStateRef State, ExplodedNode *Pred) { bool IsNew; - ExplodedNode *Node = G->getNode(Loc, State, &IsNew); + ExplodedNode *Node = G->getNode(Loc, State, false, &IsNew); if (Pred) Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. @@ -454,225 +489,181 @@ void CoreEngine::generateNode(const ProgramPoint &Loc, if (IsNew) WList->enqueue(Node); } -ExplodedNode * -GenericNodeBuilderImpl::generateNodeImpl(const ProgramState *state, - ExplodedNode *pred, - ProgramPoint programPoint, - bool asSink) { - - hasGeneratedNode = true; - bool isNew; - ExplodedNode *node = engine.getGraph().getNode(programPoint, state, &isNew); - if (pred) - node->addPredecessor(pred, engine.getGraph()); - if (isNew) { - if (asSink) { - node->markAsSink(); - sinksGenerated.push_back(node); - } - return node; - } - return 0; -} - -StmtNodeBuilder::StmtNodeBuilder(const CFGBlock *b, - unsigned idx, - ExplodedNode *N, - CoreEngine* e) - : Eng(*e), B(*b), Idx(idx), Pred(N), - 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) - if (!(*I)->isSink()) - GenerateAutoTransition(*I); -} - -void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) { +void CoreEngine::enqueueStmtNode(ExplodedNode *N, + const CFGBlock *Block, unsigned Idx) { + assert(Block); assert (!N->isSink()); // Check if this node entered a callee. if (isa<CallEnter>(N->getLocation())) { // Still use the index of the CallExpr. It's needed to create the callee // StackFrameContext. - Eng.WList->enqueue(N, &B, Idx); + WList->enqueue(N, Block, Idx); return; } // Do not create extra nodes. Move to the next CFG element. if (isa<PostInitializer>(N->getLocation())) { - Eng.WList->enqueue(N, &B, Idx+1); + WList->enqueue(N, Block, Idx+1); return; } - PostStmt Loc(getStmt(), N->getLocationContext()); + if (isa<EpsilonPoint>(N->getLocation())) { + WList->enqueue(N, Block, Idx); + return; + } + + const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>(); + const Stmt *St = CS ? CS->getStmt() : 0; + PostStmt Loc(St, N->getLocationContext()); if (Loc == N->getLocation()) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. - Eng.WList->enqueue(N, &B, Idx+1); + WList->enqueue(N, Block, Idx+1); return; } bool IsNew; - ExplodedNode *Succ = Eng.G->getNode(Loc, N->State, &IsNew); - Succ->addPredecessor(N, *Eng.G); + ExplodedNode *Succ = G->getNode(Loc, N->getState(), false, &IsNew); + Succ->addPredecessor(N, *G); if (IsNew) - Eng.WList->enqueue(Succ, &B, Idx+1); + WList->enqueue(Succ, Block, Idx+1); } -ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &Dst, - const Stmt *S, - ExplodedNode *Pred, - const ProgramState *St, - ProgramPoint::Kind K) { - - ExplodedNode *N = generateNode(S, St, Pred, K); +ExplodedNode *CoreEngine::generateCallExitNode(ExplodedNode *N) { + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast<StackFrameContext>(N->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); - if (N) { - if (BuildSinks) - N->markAsSink(); - else - Dst.Add(N); - } - - return N; -} + // Use the the callee location context. + CallExit Loc(CE, LocCtx); -ExplodedNode* -StmtNodeBuilder::generateNodeInternal(const Stmt *S, - const ProgramState *state, - ExplodedNode *Pred, - ProgramPoint::Kind K, - const ProgramPointTag *tag) { - - const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, - Pred->getLocationContext(), tag); - return generateNodeInternal(L, state, Pred); + bool isNew; + ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew); + Node->addPredecessor(N, *G); + return isNew ? Node : 0; } -ExplodedNode* -StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, - const ProgramState *State, - ExplodedNode *Pred) { - bool IsNew; - ExplodedNode *N = Eng.G->getNode(Loc, State, &IsNew); - N->addPredecessor(Pred, *Eng.G); - Deferred.erase(Pred); - if (IsNew) { - Deferred.insert(N); - return N; +void CoreEngine::enqueue(ExplodedNodeSet &Set) { + for (ExplodedNodeSet::iterator I = Set.begin(), + E = Set.end(); I != E; ++I) { + WList->enqueue(*I); } +} - return NULL; +void CoreEngine::enqueue(ExplodedNodeSet &Set, + const CFGBlock *Block, unsigned Idx) { + for (ExplodedNodeSet::iterator I = Set.begin(), + E = Set.end(); I != E; ++I) { + enqueueStmtNode(*I, Block, Idx); + } } -// This function generate a new ExplodedNode but not a new branch(block edge). -ExplodedNode *BranchNodeBuilder::generateNode(const Stmt *Condition, - const ProgramState *State) { - bool IsNew; - - ExplodedNode *Succ - = Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State, - &IsNew); - - Succ->addPredecessor(Pred, *Eng.G); - - Pred = Succ; - - if (IsNew) - return Succ; - - return NULL; +void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) { + for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { + ExplodedNode *N = *I; + // If we are in an inlined call, generate CallExit node. + if (N->getLocationContext()->getParent()) { + N = generateCallExitNode(N); + if (N) + WList->enqueue(N); + } else { + G->addEndOfPath(N); + NumPathsExplored++; + } + } } -ExplodedNode *BranchNodeBuilder::generateNode(const ProgramState *State, - bool branch) { - // If the branch has been marked infeasible we should not generate a node. - if (!isFeasible(branch)) - return NULL; +void NodeBuilder::anchor() { } +ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, + ProgramStateRef State, + ExplodedNode *FromN, + bool MarkAsSink) { + HasGeneratedNodes = true; bool IsNew; + ExplodedNode *N = C.Eng.G->getNode(Loc, State, MarkAsSink, &IsNew); + N->addPredecessor(FromN, *C.Eng.G); + Frontier.erase(FromN); - ExplodedNode *Succ = - Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()), - State, &IsNew); + if (!IsNew) + return 0; - Succ->addPredecessor(Pred, *Eng.G); + if (!MarkAsSink) + Frontier.Add(N); - if (branch) - GeneratedTrue = true; - else - GeneratedFalse = true; + return N; +} - if (IsNew) { - Deferred.push_back(Succ); - return Succ; - } +void NodeBuilderWithSinks::anchor() { } - return NULL; +StmtNodeBuilder::~StmtNodeBuilder() { + if (EnclosingBldr) + for (ExplodedNodeSet::iterator I = Frontier.begin(), + E = Frontier.end(); I != E; ++I ) + EnclosingBldr->addNodes(*I); } -BranchNodeBuilder::~BranchNodeBuilder() { - if (!GeneratedTrue) generateNode(Pred->State, true); - if (!GeneratedFalse) generateNode(Pred->State, false); +void BranchNodeBuilder::anchor() { } - for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) - if (!(*I)->isSink()) Eng.WList->enqueue(*I); -} +ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State, + bool branch, + ExplodedNode *NodePred) { + // If the branch has been marked infeasible we should not generate a node. + if (!isFeasible(branch)) + return NULL; + ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF, + NodePred->getLocationContext()); + ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred); + return Succ; +} ExplodedNode* IndirectGotoNodeBuilder::generateNode(const iterator &I, - const ProgramState *St, - bool isSink) { + ProgramStateRef St, + bool IsSink) { bool IsNew; - ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), - Pred->getLocationContext()), St, &IsNew); - + Pred->getLocationContext()), St, + IsSink, &IsNew); Succ->addPredecessor(Pred, *Eng.G); - if (IsNew) { + if (!IsNew) + return 0; - if (isSink) - Succ->markAsSink(); - else - Eng.WList->enqueue(Succ); - - return Succ; - } + if (!IsSink) + Eng.WList->enqueue(Succ); - return NULL; + return Succ; } ExplodedNode* SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, - const ProgramState *St) { + ProgramStateRef St) { bool IsNew; ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), - Pred->getLocationContext()), - St, &IsNew); + Pred->getLocationContext()), St, + false, &IsNew); Succ->addPredecessor(Pred, *Eng.G); - if (IsNew) { - Eng.WList->enqueue(Succ); - return Succ; - } - return NULL; + if (!IsNew) + return 0; + + Eng.WList->enqueue(Succ); + return Succ; } ExplodedNode* -SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St, - bool isSink) { +SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, + bool IsSink) { // Get the block for the default case. assert(Src->succ_rbegin() != Src->succ_rend()); CFGBlock *DefaultBlock = *Src->succ_rbegin(); @@ -683,145 +674,16 @@ SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St, return NULL; bool IsNew; - ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, - Pred->getLocationContext()), St, &IsNew); + Pred->getLocationContext()), St, + IsSink, &IsNew); Succ->addPredecessor(Pred, *Eng.G); - if (IsNew) { - if (isSink) - Succ->markAsSink(); - else - Eng.WList->enqueue(Succ); - - return Succ; - } - - 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<StackFrameContext>(Pred->getLocationContext()); - const Stmt *CE = LocCtx->getCallSite(); + if (!IsNew) + return 0; - // 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() != - Pred->getLocationContext()->getTranslationUnit()) { - // Create a new engine. We must be careful that the new engine should not - // reference data structures owned by the old engine. - - AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager(); - - // Get the callee's translation unit. - idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit(); - - // Create a new AnalysisManager with components of the callee's - // TranslationUnit. - // The Diagnostic is actually shared when we create ASTUnits from AST files. - AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr); - - // Create the new engine. - // FIXME: This cast isn't really safe. - bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled(); - ExprEngine NewEng(AMgr, GCEnabled); - - // Create the new LocationContext. - AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), - CalleeCtx->getTranslationUnit()); - const StackFrameContext *OldLocCtx = CalleeCtx; - const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx, - OldLocCtx->getParent(), - OldLocCtx->getCallSite(), - OldLocCtx->getCallSiteBlock(), - OldLocCtx->getIndex()); - - // Now create an initial state for the new engine. - const ProgramState *NewState = - NewEng.getStateManager().MarshalState(state, NewLocCtx); - ExplodedNodeSet ReturnNodes; - NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), - NewState, ReturnNodes); - return; - } - - // Get the callee entry block. - const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry()); - assert(Entry->empty()); - assert(Entry->succ_size() == 1); - - // Get the solitary successor. - const CFGBlock *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the callee. - BlockEdge Loc(Entry, SuccB, CalleeCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G); - - if (isNew) - Eng.WList->enqueue(Node); -} + if (!IsSink) + Eng.WList->enqueue(Succ); -void CallExitNodeBuilder::generateNode(const ProgramState *state) { - // Get the callee's location context. - const StackFrameContext *LocCtx - = cast<StackFrameContext>(Pred->getLocationContext()); - // When exiting an implicit automatic obj dtor call, the callsite is the Stmt - // that triggers the dtor. - PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G); - if (isNew) - Eng.WList->enqueue(Node, LocCtx->getCallSiteBlock(), - LocCtx->getIndex() + 1); + return Succ; } |