clang API Documentation
00001 //==- CoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a generic engine for intraprocedural, path-sensitive, 00011 // dataflow analysis via graph reachability engine. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #define DEBUG_TYPE "CoreEngine" 00016 00017 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 00020 #include "clang/AST/Expr.h" 00021 #include "clang/AST/StmtCXX.h" 00022 #include "llvm/Support/Casting.h" 00023 #include "llvm/ADT/DenseMap.h" 00024 #include "llvm/ADT/Statistic.h" 00025 00026 using namespace clang; 00027 using namespace ento; 00028 00029 STATISTIC(NumReachedMaxSteps, 00030 "The # of times we reached the max number of steps."); 00031 STATISTIC(NumPathsExplored, 00032 "The # of paths explored by the analyzer."); 00033 00034 //===----------------------------------------------------------------------===// 00035 // Worklist classes for exploration of reachable states. 00036 //===----------------------------------------------------------------------===// 00037 00038 WorkList::Visitor::~Visitor() {} 00039 00040 namespace { 00041 class DFS : public WorkList { 00042 SmallVector<WorkListUnit,20> Stack; 00043 public: 00044 virtual bool hasWork() const { 00045 return !Stack.empty(); 00046 } 00047 00048 virtual void enqueue(const WorkListUnit& U) { 00049 Stack.push_back(U); 00050 } 00051 00052 virtual WorkListUnit dequeue() { 00053 assert (!Stack.empty()); 00054 const WorkListUnit& U = Stack.back(); 00055 Stack.pop_back(); // This technically "invalidates" U, but we are fine. 00056 return U; 00057 } 00058 00059 virtual bool visitItemsInWorkList(Visitor &V) { 00060 for (SmallVectorImpl<WorkListUnit>::iterator 00061 I = Stack.begin(), E = Stack.end(); I != E; ++I) { 00062 if (V.visit(*I)) 00063 return true; 00064 } 00065 return false; 00066 } 00067 }; 00068 00069 class BFS : public WorkList { 00070 std::deque<WorkListUnit> Queue; 00071 public: 00072 virtual bool hasWork() const { 00073 return !Queue.empty(); 00074 } 00075 00076 virtual void enqueue(const WorkListUnit& U) { 00077 Queue.push_front(U); 00078 } 00079 00080 virtual WorkListUnit dequeue() { 00081 WorkListUnit U = Queue.front(); 00082 Queue.pop_front(); 00083 return U; 00084 } 00085 00086 virtual bool visitItemsInWorkList(Visitor &V) { 00087 for (std::deque<WorkListUnit>::iterator 00088 I = Queue.begin(), E = Queue.end(); I != E; ++I) { 00089 if (V.visit(*I)) 00090 return true; 00091 } 00092 return false; 00093 } 00094 }; 00095 00096 } // end anonymous namespace 00097 00098 // Place the dstor for WorkList here because it contains virtual member 00099 // functions, and we the code for the dstor generated in one compilation unit. 00100 WorkList::~WorkList() {} 00101 00102 WorkList *WorkList::makeDFS() { return new DFS(); } 00103 WorkList *WorkList::makeBFS() { return new BFS(); } 00104 00105 namespace { 00106 class BFSBlockDFSContents : public WorkList { 00107 std::deque<WorkListUnit> Queue; 00108 SmallVector<WorkListUnit,20> Stack; 00109 public: 00110 virtual bool hasWork() const { 00111 return !Queue.empty() || !Stack.empty(); 00112 } 00113 00114 virtual void enqueue(const WorkListUnit& U) { 00115 if (isa<BlockEntrance>(U.getNode()->getLocation())) 00116 Queue.push_front(U); 00117 else 00118 Stack.push_back(U); 00119 } 00120 00121 virtual WorkListUnit dequeue() { 00122 // Process all basic blocks to completion. 00123 if (!Stack.empty()) { 00124 const WorkListUnit& U = Stack.back(); 00125 Stack.pop_back(); // This technically "invalidates" U, but we are fine. 00126 return U; 00127 } 00128 00129 assert(!Queue.empty()); 00130 // Don't use const reference. The subsequent pop_back() might make it 00131 // unsafe. 00132 WorkListUnit U = Queue.front(); 00133 Queue.pop_front(); 00134 return U; 00135 } 00136 virtual bool visitItemsInWorkList(Visitor &V) { 00137 for (SmallVectorImpl<WorkListUnit>::iterator 00138 I = Stack.begin(), E = Stack.end(); I != E; ++I) { 00139 if (V.visit(*I)) 00140 return true; 00141 } 00142 for (std::deque<WorkListUnit>::iterator 00143 I = Queue.begin(), E = Queue.end(); I != E; ++I) { 00144 if (V.visit(*I)) 00145 return true; 00146 } 00147 return false; 00148 } 00149 00150 }; 00151 } // end anonymous namespace 00152 00153 WorkList* WorkList::makeBFSBlockDFSContents() { 00154 return new BFSBlockDFSContents(); 00155 } 00156 00157 //===----------------------------------------------------------------------===// 00158 // Core analysis engine. 00159 //===----------------------------------------------------------------------===// 00160 00161 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. 00162 bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, 00163 ProgramStateRef InitState) { 00164 00165 if (G->num_roots() == 0) { // Initialize the analysis by constructing 00166 // the root if none exists. 00167 00168 const CFGBlock *Entry = &(L->getCFG()->getEntry()); 00169 00170 assert (Entry->empty() && 00171 "Entry block must be empty."); 00172 00173 assert (Entry->succ_size() == 1 && 00174 "Entry block must have 1 successor."); 00175 00176 // Mark the entry block as visited. 00177 FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(), 00178 L->getDecl(), 00179 L->getCFG()->getNumBlockIDs()); 00180 00181 // Get the solitary successor. 00182 const CFGBlock *Succ = *(Entry->succ_begin()); 00183 00184 // Construct an edge representing the 00185 // starting location in the function. 00186 BlockEdge StartLoc(Entry, Succ, L); 00187 00188 // Set the current block counter to being empty. 00189 WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); 00190 00191 if (!InitState) 00192 // Generate the root. 00193 generateNode(StartLoc, SubEng.getInitialState(L), 0); 00194 else 00195 generateNode(StartLoc, InitState, 0); 00196 } 00197 00198 // Check if we have a steps limit 00199 bool UnlimitedSteps = Steps == 0; 00200 00201 while (WList->hasWork()) { 00202 if (!UnlimitedSteps) { 00203 if (Steps == 0) { 00204 NumReachedMaxSteps++; 00205 break; 00206 } 00207 --Steps; 00208 } 00209 00210 const WorkListUnit& WU = WList->dequeue(); 00211 00212 // Set the current block counter. 00213 WList->setBlockCounter(WU.getBlockCounter()); 00214 00215 // Retrieve the node. 00216 ExplodedNode *Node = WU.getNode(); 00217 00218 dispatchWorkItem(Node, Node->getLocation(), WU); 00219 } 00220 SubEng.processEndWorklist(hasWorkRemaining()); 00221 return WList->hasWork(); 00222 } 00223 00224 void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, 00225 const WorkListUnit& WU) { 00226 // Dispatch on the location type. 00227 switch (Loc.getKind()) { 00228 case ProgramPoint::BlockEdgeKind: 00229 HandleBlockEdge(cast<BlockEdge>(Loc), Pred); 00230 break; 00231 00232 case ProgramPoint::BlockEntranceKind: 00233 HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred); 00234 break; 00235 00236 case ProgramPoint::BlockExitKind: 00237 assert (false && "BlockExit location never occur in forward analysis."); 00238 break; 00239 00240 case ProgramPoint::CallEnterKind: { 00241 CallEnter CEnter = cast<CallEnter>(Loc); 00242 if (AnalyzedCallees) 00243 if (const CallExpr* CE = 00244 dyn_cast_or_null<CallExpr>(CEnter.getCallExpr())) 00245 if (const Decl *CD = CE->getCalleeDecl()) 00246 AnalyzedCallees->insert(CD); 00247 SubEng.processCallEnter(CEnter, Pred); 00248 break; 00249 } 00250 00251 case ProgramPoint::CallExitBeginKind: 00252 SubEng.processCallExit(Pred); 00253 break; 00254 00255 case ProgramPoint::EpsilonKind: { 00256 assert(Pred->hasSinglePred() && 00257 "Assume epsilon has exactly one predecessor by construction"); 00258 ExplodedNode *PNode = Pred->getFirstPred(); 00259 dispatchWorkItem(Pred, PNode->getLocation(), WU); 00260 break; 00261 } 00262 default: 00263 assert(isa<PostStmt>(Loc) || 00264 isa<PostInitializer>(Loc)); 00265 HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred); 00266 break; 00267 } 00268 } 00269 00270 bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, 00271 unsigned Steps, 00272 ProgramStateRef InitState, 00273 ExplodedNodeSet &Dst) { 00274 bool DidNotFinish = ExecuteWorkList(L, Steps, InitState); 00275 for (ExplodedGraph::eop_iterator I = G->eop_begin(), 00276 E = G->eop_end(); I != E; ++I) { 00277 Dst.Add(*I); 00278 } 00279 return DidNotFinish; 00280 } 00281 00282 void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { 00283 00284 const CFGBlock *Blk = L.getDst(); 00285 NodeBuilderContext BuilderCtx(*this, Blk, Pred); 00286 00287 // Mark this block as visited. 00288 const LocationContext *LC = Pred->getLocationContext(); 00289 FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), 00290 LC->getDecl(), 00291 LC->getCFG()->getNumBlockIDs()); 00292 00293 // Check if we are entering the EXIT block. 00294 if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { 00295 00296 assert (L.getLocationContext()->getCFG()->getExit().size() == 0 00297 && "EXIT block cannot contain Stmts."); 00298 00299 // Process the final state transition. 00300 SubEng.processEndOfFunction(BuilderCtx); 00301 00302 // This path is done. Don't enqueue any more nodes. 00303 return; 00304 } 00305 00306 // Call into the SubEngine to process entering the CFGBlock. 00307 ExplodedNodeSet dstNodes; 00308 BlockEntrance BE(Blk, Pred->getLocationContext()); 00309 NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); 00310 SubEng.processCFGBlockEntrance(L, nodeBuilder); 00311 00312 // Auto-generate a node. 00313 if (!nodeBuilder.hasGeneratedNodes()) { 00314 nodeBuilder.generateNode(Pred->State, Pred); 00315 } 00316 00317 // Enqueue nodes onto the worklist. 00318 enqueue(dstNodes); 00319 } 00320 00321 void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, 00322 ExplodedNode *Pred) { 00323 00324 // Increment the block counter. 00325 const LocationContext *LC = Pred->getLocationContext(); 00326 unsigned BlockId = L.getBlock()->getBlockID(); 00327 BlockCounter Counter = WList->getBlockCounter(); 00328 Counter = BCounterFactory.IncrementCount(Counter, LC->getCurrentStackFrame(), 00329 BlockId); 00330 WList->setBlockCounter(Counter); 00331 00332 // Process the entrance of the block. 00333 if (CFGElement E = L.getFirstElement()) { 00334 NodeBuilderContext Ctx(*this, L.getBlock(), Pred); 00335 SubEng.processCFGElement(E, Pred, 0, &Ctx); 00336 } 00337 else 00338 HandleBlockExit(L.getBlock(), Pred); 00339 } 00340 00341 void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { 00342 00343 if (const Stmt *Term = B->getTerminator()) { 00344 switch (Term->getStmtClass()) { 00345 default: 00346 llvm_unreachable("Analysis for this terminator not implemented."); 00347 00348 case Stmt::BinaryOperatorClass: // '&&' and '||' 00349 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred); 00350 return; 00351 00352 case Stmt::BinaryConditionalOperatorClass: 00353 case Stmt::ConditionalOperatorClass: 00354 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(), 00355 Term, B, Pred); 00356 return; 00357 00358 // FIXME: Use constant-folding in CFG construction to simplify this 00359 // case. 00360 00361 case Stmt::ChooseExprClass: 00362 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred); 00363 return; 00364 00365 case Stmt::CXXTryStmtClass: { 00366 // Generate a node for each of the successors. 00367 // Our logic for EH analysis can certainly be improved. 00368 for (CFGBlock::const_succ_iterator it = B->succ_begin(), 00369 et = B->succ_end(); it != et; ++it) { 00370 if (const CFGBlock *succ = *it) { 00371 generateNode(BlockEdge(B, succ, Pred->getLocationContext()), 00372 Pred->State, Pred); 00373 } 00374 } 00375 return; 00376 } 00377 00378 case Stmt::DoStmtClass: 00379 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred); 00380 return; 00381 00382 case Stmt::CXXForRangeStmtClass: 00383 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred); 00384 return; 00385 00386 case Stmt::ForStmtClass: 00387 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred); 00388 return; 00389 00390 case Stmt::ContinueStmtClass: 00391 case Stmt::BreakStmtClass: 00392 case Stmt::GotoStmtClass: 00393 break; 00394 00395 case Stmt::IfStmtClass: 00396 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred); 00397 return; 00398 00399 case Stmt::IndirectGotoStmtClass: { 00400 // Only 1 successor: the indirect goto dispatch block. 00401 assert (B->succ_size() == 1); 00402 00403 IndirectGotoNodeBuilder 00404 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(), 00405 *(B->succ_begin()), this); 00406 00407 SubEng.processIndirectGoto(builder); 00408 return; 00409 } 00410 00411 case Stmt::ObjCForCollectionStmtClass: { 00412 // In the case of ObjCForCollectionStmt, it appears twice in a CFG: 00413 // 00414 // (1) inside a basic block, which represents the binding of the 00415 // 'element' variable to a value. 00416 // (2) in a terminator, which represents the branch. 00417 // 00418 // For (1), subengines will bind a value (i.e., 0 or 1) indicating 00419 // whether or not collection contains any more elements. We cannot 00420 // just test to see if the element is nil because a container can 00421 // contain nil elements. 00422 HandleBranch(Term, Term, B, Pred); 00423 return; 00424 } 00425 00426 case Stmt::SwitchStmtClass: { 00427 SwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(), 00428 this); 00429 00430 SubEng.processSwitch(builder); 00431 return; 00432 } 00433 00434 case Stmt::WhileStmtClass: 00435 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred); 00436 return; 00437 } 00438 } 00439 00440 assert (B->succ_size() == 1 && 00441 "Blocks with no terminator should have at most 1 successor."); 00442 00443 generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()), 00444 Pred->State, Pred); 00445 } 00446 00447 void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, 00448 const CFGBlock * B, ExplodedNode *Pred) { 00449 assert(B->succ_size() == 2); 00450 NodeBuilderContext Ctx(*this, B, Pred); 00451 ExplodedNodeSet Dst; 00452 SubEng.processBranch(Cond, Term, Ctx, Pred, Dst, 00453 *(B->succ_begin()), *(B->succ_begin()+1)); 00454 // Enqueue the new frontier onto the worklist. 00455 enqueue(Dst); 00456 } 00457 00458 void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, 00459 ExplodedNode *Pred) { 00460 assert(B); 00461 assert(!B->empty()); 00462 00463 if (StmtIdx == B->size()) 00464 HandleBlockExit(B, Pred); 00465 else { 00466 NodeBuilderContext Ctx(*this, B, Pred); 00467 SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx); 00468 } 00469 } 00470 00471 /// generateNode - Utility method to generate nodes, hook up successors, 00472 /// and add nodes to the worklist. 00473 void CoreEngine::generateNode(const ProgramPoint &Loc, 00474 ProgramStateRef State, 00475 ExplodedNode *Pred) { 00476 00477 bool IsNew; 00478 ExplodedNode *Node = G->getNode(Loc, State, false, &IsNew); 00479 00480 if (Pred) 00481 Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. 00482 else { 00483 assert (IsNew); 00484 G->addRoot(Node); // 'Node' has no predecessor. Make it a root. 00485 } 00486 00487 // Only add 'Node' to the worklist if it was freshly generated. 00488 if (IsNew) WList->enqueue(Node); 00489 } 00490 00491 void CoreEngine::enqueueStmtNode(ExplodedNode *N, 00492 const CFGBlock *Block, unsigned Idx) { 00493 assert(Block); 00494 assert (!N->isSink()); 00495 00496 // Check if this node entered a callee. 00497 if (isa<CallEnter>(N->getLocation())) { 00498 // Still use the index of the CallExpr. It's needed to create the callee 00499 // StackFrameContext. 00500 WList->enqueue(N, Block, Idx); 00501 return; 00502 } 00503 00504 // Do not create extra nodes. Move to the next CFG element. 00505 if (isa<PostInitializer>(N->getLocation())) { 00506 WList->enqueue(N, Block, Idx+1); 00507 return; 00508 } 00509 00510 if (isa<EpsilonPoint>(N->getLocation())) { 00511 WList->enqueue(N, Block, Idx); 00512 return; 00513 } 00514 00515 const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>(); 00516 const Stmt *St = CS ? CS->getStmt() : 0; 00517 PostStmt Loc(St, N->getLocationContext()); 00518 00519 if (Loc == N->getLocation()) { 00520 // Note: 'N' should be a fresh node because otherwise it shouldn't be 00521 // a member of Deferred. 00522 WList->enqueue(N, Block, Idx+1); 00523 return; 00524 } 00525 00526 bool IsNew; 00527 ExplodedNode *Succ = G->getNode(Loc, N->getState(), false, &IsNew); 00528 Succ->addPredecessor(N, *G); 00529 00530 if (IsNew) 00531 WList->enqueue(Succ, Block, Idx+1); 00532 } 00533 00534 ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) { 00535 // Create a CallExitBegin node and enqueue it. 00536 const StackFrameContext *LocCtx 00537 = cast<StackFrameContext>(N->getLocationContext()); 00538 const Stmt *CE = LocCtx->getCallSite(); 00539 00540 // Use the the callee location context. 00541 CallExitBegin Loc(CE, LocCtx); 00542 00543 bool isNew; 00544 ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew); 00545 Node->addPredecessor(N, *G); 00546 return isNew ? Node : 0; 00547 } 00548 00549 00550 void CoreEngine::enqueue(ExplodedNodeSet &Set) { 00551 for (ExplodedNodeSet::iterator I = Set.begin(), 00552 E = Set.end(); I != E; ++I) { 00553 WList->enqueue(*I); 00554 } 00555 } 00556 00557 void CoreEngine::enqueue(ExplodedNodeSet &Set, 00558 const CFGBlock *Block, unsigned Idx) { 00559 for (ExplodedNodeSet::iterator I = Set.begin(), 00560 E = Set.end(); I != E; ++I) { 00561 enqueueStmtNode(*I, Block, Idx); 00562 } 00563 } 00564 00565 void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) { 00566 for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { 00567 ExplodedNode *N = *I; 00568 // If we are in an inlined call, generate CallExitBegin node. 00569 if (N->getLocationContext()->getParent()) { 00570 N = generateCallExitBeginNode(N); 00571 if (N) 00572 WList->enqueue(N); 00573 } else { 00574 // TODO: We should run remove dead bindings here. 00575 G->addEndOfPath(N); 00576 NumPathsExplored++; 00577 } 00578 } 00579 } 00580 00581 00582 void NodeBuilder::anchor() { } 00583 00584 ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, 00585 ProgramStateRef State, 00586 ExplodedNode *FromN, 00587 bool MarkAsSink) { 00588 HasGeneratedNodes = true; 00589 bool IsNew; 00590 ExplodedNode *N = C.Eng.G->getNode(Loc, State, MarkAsSink, &IsNew); 00591 N->addPredecessor(FromN, *C.Eng.G); 00592 Frontier.erase(FromN); 00593 00594 if (!IsNew) 00595 return 0; 00596 00597 if (!MarkAsSink) 00598 Frontier.Add(N); 00599 00600 return N; 00601 } 00602 00603 void NodeBuilderWithSinks::anchor() { } 00604 00605 StmtNodeBuilder::~StmtNodeBuilder() { 00606 if (EnclosingBldr) 00607 for (ExplodedNodeSet::iterator I = Frontier.begin(), 00608 E = Frontier.end(); I != E; ++I ) 00609 EnclosingBldr->addNodes(*I); 00610 } 00611 00612 void BranchNodeBuilder::anchor() { } 00613 00614 ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State, 00615 bool branch, 00616 ExplodedNode *NodePred) { 00617 // If the branch has been marked infeasible we should not generate a node. 00618 if (!isFeasible(branch)) 00619 return NULL; 00620 00621 ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF, 00622 NodePred->getLocationContext()); 00623 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred); 00624 return Succ; 00625 } 00626 00627 ExplodedNode* 00628 IndirectGotoNodeBuilder::generateNode(const iterator &I, 00629 ProgramStateRef St, 00630 bool IsSink) { 00631 bool IsNew; 00632 ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), 00633 Pred->getLocationContext()), St, 00634 IsSink, &IsNew); 00635 Succ->addPredecessor(Pred, *Eng.G); 00636 00637 if (!IsNew) 00638 return 0; 00639 00640 if (!IsSink) 00641 Eng.WList->enqueue(Succ); 00642 00643 return Succ; 00644 } 00645 00646 00647 ExplodedNode* 00648 SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, 00649 ProgramStateRef St) { 00650 00651 bool IsNew; 00652 ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), 00653 Pred->getLocationContext()), St, 00654 false, &IsNew); 00655 Succ->addPredecessor(Pred, *Eng.G); 00656 if (!IsNew) 00657 return 0; 00658 00659 Eng.WList->enqueue(Succ); 00660 return Succ; 00661 } 00662 00663 00664 ExplodedNode* 00665 SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, 00666 bool IsSink) { 00667 // Get the block for the default case. 00668 assert(Src->succ_rbegin() != Src->succ_rend()); 00669 CFGBlock *DefaultBlock = *Src->succ_rbegin(); 00670 00671 // Sanity check for default blocks that are unreachable and not caught 00672 // by earlier stages. 00673 if (!DefaultBlock) 00674 return NULL; 00675 00676 bool IsNew; 00677 ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, 00678 Pred->getLocationContext()), St, 00679 IsSink, &IsNew); 00680 Succ->addPredecessor(Pred, *Eng.G); 00681 00682 if (!IsNew) 00683 return 0; 00684 00685 if (!IsSink) 00686 Eng.WList->enqueue(Succ); 00687 00688 return Succ; 00689 }