clang API Documentation
00001 //=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- 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 ExprEngine's support for calls and returns. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00015 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 00016 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 00017 #include "clang/AST/DeclCXX.h" 00018 #include "llvm/ADT/SmallSet.h" 00019 #include "llvm/Support/SaveAndRestore.h" 00020 00021 using namespace clang; 00022 using namespace ento; 00023 00024 void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { 00025 // Get the entry block in the CFG of the callee. 00026 const StackFrameContext *calleeCtx = CE.getCalleeContext(); 00027 const CFG *CalleeCFG = calleeCtx->getCFG(); 00028 const CFGBlock *Entry = &(CalleeCFG->getEntry()); 00029 00030 // Validate the CFG. 00031 assert(Entry->empty()); 00032 assert(Entry->succ_size() == 1); 00033 00034 // Get the solitary sucessor. 00035 const CFGBlock *Succ = *(Entry->succ_begin()); 00036 00037 // Construct an edge representing the starting location in the callee. 00038 BlockEdge Loc(Entry, Succ, calleeCtx); 00039 00040 // Construct a new state which contains the mapping from actual to 00041 // formal arguments. 00042 const LocationContext *callerCtx = Pred->getLocationContext(); 00043 ProgramStateRef state = Pred->getState()->enterStackFrame(callerCtx, 00044 calleeCtx); 00045 00046 // Construct a new node and add it to the worklist. 00047 bool isNew; 00048 ExplodedNode *Node = G.getNode(Loc, state, false, &isNew); 00049 Node->addPredecessor(Pred, G); 00050 if (isNew) 00051 Engine.getWorkList()->enqueue(Node); 00052 } 00053 00054 // Find the last statement on the path to the exploded node and the 00055 // corresponding Block. 00056 static std::pair<const Stmt*, 00057 const CFGBlock*> getLastStmt(const ExplodedNode *Node) { 00058 const Stmt *S = 0; 00059 const CFGBlock *Blk = 0; 00060 const StackFrameContext *SF = 00061 Node->getLocation().getLocationContext()->getCurrentStackFrame(); 00062 while (Node) { 00063 const ProgramPoint &PP = Node->getLocation(); 00064 // Skip any BlockEdges, empty blocks, and the CallExitBegin node. 00065 if (isa<BlockEdge>(PP) || isa<CallExitBegin>(PP) || isa<BlockEntrance>(PP)){ 00066 assert(Node->pred_size() == 1); 00067 Node = *Node->pred_begin(); 00068 continue; 00069 } 00070 // If we reached the CallEnter, the function has no statements. 00071 if (isa<CallEnter>(PP)) 00072 break; 00073 if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { 00074 S = SP->getStmt(); 00075 // Now, get the enclosing basic block. 00076 while (Node && Node->pred_size() >=1 ) { 00077 const ProgramPoint &PP = Node->getLocation(); 00078 if (isa<BlockEdge>(PP) && 00079 (PP.getLocationContext()->getCurrentStackFrame() == SF)) { 00080 BlockEdge &EPP = cast<BlockEdge>(PP); 00081 Blk = EPP.getDst(); 00082 break; 00083 } 00084 Node = *Node->pred_begin(); 00085 } 00086 break; 00087 } 00088 break; 00089 } 00090 return std::pair<const Stmt*, const CFGBlock*>(S, Blk); 00091 } 00092 00093 /// The call exit is simulated with a sequence of nodes, which occur between 00094 /// CallExitBegin and CallExitEnd. The following operations occur between the 00095 /// two program points: 00096 /// 1. CallExitBegin (triggers the start of call exit sequence) 00097 /// 2. Bind the return value 00098 /// 3. Run Remove dead bindings to clean up the dead symbols from the callee. 00099 /// 4. CallExitEnd (switch to the caller context) 00100 /// 5. PostStmt<CallExpr> 00101 void ExprEngine::processCallExit(ExplodedNode *CEBNode) { 00102 // Step 1 CEBNode was generated before the call. 00103 00104 const StackFrameContext *calleeCtx = 00105 CEBNode->getLocationContext()->getCurrentStackFrame(); 00106 const LocationContext *callerCtx = calleeCtx->getParent(); 00107 const Stmt *CE = calleeCtx->getCallSite(); 00108 ProgramStateRef state = CEBNode->getState(); 00109 // Find the last statement in the function and the corresponding basic block. 00110 const Stmt *LastSt = 0; 00111 const CFGBlock *Blk = 0; 00112 llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); 00113 00114 // Step 2: generate node with binded return value: CEBNode -> BindedRetNode. 00115 00116 // If the callee returns an expression, bind its value to CallExpr. 00117 if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { 00118 const LocationContext *LCtx = CEBNode->getLocationContext(); 00119 SVal V = state->getSVal(RS, LCtx); 00120 state = state->BindExpr(CE, callerCtx, V); 00121 } 00122 00123 // Bind the constructed object value to CXXConstructExpr. 00124 if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { 00125 const CXXThisRegion *ThisR = 00126 getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); 00127 00128 SVal ThisV = state->getSVal(ThisR); 00129 // Always bind the region to the CXXConstructExpr. 00130 state = state->BindExpr(CCE, CEBNode->getLocationContext(), ThisV); 00131 } 00132 00133 static SimpleProgramPointTag retValBindTag("ExprEngine : Bind Return Value"); 00134 PostStmt Loc(LastSt, calleeCtx, &retValBindTag); 00135 bool isNew; 00136 ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); 00137 BindedRetNode->addPredecessor(CEBNode, G); 00138 if (!isNew) 00139 return; 00140 00141 // Step 3: BindedRetNode -> CleanedNodes 00142 // If we can find a statement and a block in the inlined function, run remove 00143 // dead bindings before returning from the call. This is important to ensure 00144 // that we report the issues such as leaks in the stack contexts in which 00145 // they occurred. 00146 ExplodedNodeSet CleanedNodes; 00147 if (LastSt && Blk) { 00148 NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); 00149 currentBuilderContext = &Ctx; 00150 // Here, we call the Symbol Reaper with 0 statement and caller location 00151 // context, telling it to clean up everything in the callee's context 00152 // (and it's children). We use LastStmt as a diagnostic statement, which 00153 // which the PreStmtPurge Dead point will be associated. 00154 removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt, 00155 ProgramPoint::PostStmtPurgeDeadSymbolsKind); 00156 currentBuilderContext = 0; 00157 } 00158 00159 for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), 00160 E = CleanedNodes.end(); I != E; ++I) { 00161 00162 // Step 4: Generate the CallExit and leave the callee's context. 00163 // CleanedNodes -> CEENode 00164 CallExitEnd Loc(CE, callerCtx); 00165 bool isNew; 00166 ExplodedNode *CEENode = G.getNode(Loc, (*I)->getState(), false, &isNew); 00167 CEENode->addPredecessor(*I, G); 00168 if (!isNew) 00169 return; 00170 00171 // Step 5: Perform the post-condition check of the CallExpr and enqueue the 00172 // result onto the work list. 00173 // CEENode -> Dst -> WorkList 00174 ExplodedNodeSet Dst; 00175 NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); 00176 SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext, 00177 &Ctx); 00178 SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); 00179 00180 getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true); 00181 00182 // Enqueue the next element in the block. 00183 for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); 00184 PSI != PSE; ++PSI) { 00185 Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), 00186 calleeCtx->getIndex()+1); 00187 } 00188 } 00189 } 00190 00191 static unsigned getNumberStackFrames(const LocationContext *LCtx) { 00192 unsigned count = 0; 00193 while (LCtx) { 00194 if (isa<StackFrameContext>(LCtx)) 00195 ++count; 00196 LCtx = LCtx->getParent(); 00197 } 00198 return count; 00199 } 00200 00201 // Determine if we should inline the call. 00202 bool ExprEngine::shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred) { 00203 AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD); 00204 const CFG *CalleeCFG = CalleeADC->getCFG(); 00205 00206 // It is possible that the CFG cannot be constructed. 00207 // Be safe, and check if the CalleeCFG is valid. 00208 if (!CalleeCFG) 00209 return false; 00210 00211 if (getNumberStackFrames(Pred->getLocationContext()) 00212 == AMgr.InlineMaxStackDepth) 00213 return false; 00214 00215 if (Engine.FunctionSummaries->hasReachedMaxBlockCount(FD)) 00216 return false; 00217 00218 if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize) 00219 return false; 00220 00221 return true; 00222 } 00223 00224 // For now, skip inlining variadic functions. 00225 // We also don't inline blocks. 00226 static bool shouldInlineCallExpr(const CallExpr *CE, ExprEngine *E) { 00227 if (!E->getAnalysisManager().shouldInlineCall()) 00228 return false; 00229 QualType callee = CE->getCallee()->getType(); 00230 const FunctionProtoType *FT = 0; 00231 if (const PointerType *PT = callee->getAs<PointerType>()) 00232 FT = dyn_cast<FunctionProtoType>(PT->getPointeeType()); 00233 else if (const BlockPointerType *BT = callee->getAs<BlockPointerType>()) { 00234 // FIXME: inline blocks. 00235 // FT = dyn_cast<FunctionProtoType>(BT->getPointeeType()); 00236 (void) BT; 00237 return false; 00238 } 00239 // If we have no prototype, assume the function is okay. 00240 if (!FT) 00241 return true; 00242 00243 // Skip inlining of variadic functions. 00244 return !FT->isVariadic(); 00245 } 00246 00247 bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, 00248 const CallExpr *CE, 00249 ExplodedNode *Pred) { 00250 if (!shouldInlineCallExpr(CE, this)) 00251 return false; 00252 00253 ProgramStateRef state = Pred->getState(); 00254 const Expr *Callee = CE->getCallee(); 00255 const FunctionDecl *FD = 00256 state->getSVal(Callee, Pred->getLocationContext()).getAsFunctionDecl(); 00257 if (!FD || !FD->hasBody(FD)) 00258 return false; 00259 00260 switch (CE->getStmtClass()) { 00261 default: 00262 // FIXME: Handle C++. 00263 break; 00264 case Stmt::CallExprClass: { 00265 if (!shouldInlineDecl(FD, Pred)) 00266 return false; 00267 00268 // Construct a new stack frame for the callee. 00269 AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD); 00270 const StackFrameContext *CallerSFC = 00271 Pred->getLocationContext()->getCurrentStackFrame(); 00272 const StackFrameContext *CalleeSFC = 00273 CalleeADC->getStackFrame(CallerSFC, CE, 00274 currentBuilderContext->getBlock(), 00275 currentStmtIdx); 00276 00277 CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext()); 00278 bool isNew; 00279 if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) { 00280 N->addPredecessor(Pred, G); 00281 if (isNew) 00282 Engine.getWorkList()->enqueue(N); 00283 } 00284 return true; 00285 } 00286 } 00287 return false; 00288 } 00289 00290 static bool isPointerToConst(const ParmVarDecl *ParamDecl) { 00291 QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); 00292 if (PointeeTy != QualType() && PointeeTy.isConstQualified() && 00293 !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) { 00294 return true; 00295 } 00296 return false; 00297 } 00298 00299 // Try to retrieve the function declaration and find the function parameter 00300 // types which are pointers/references to a non-pointer const. 00301 // We do not invalidate the corresponding argument regions. 00302 static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, 00303 const CallOrObjCMessage &Call) { 00304 const Decl *CallDecl = Call.getDecl(); 00305 if (!CallDecl) 00306 return; 00307 00308 if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { 00309 const IdentifierInfo *II = FDecl->getIdentifier(); 00310 00311 // List the cases, where the region should be invalidated even if the 00312 // argument is const. 00313 if (II) { 00314 StringRef FName = II->getName(); 00315 // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a 00316 // value into thread local storage. The value can later be retrieved with 00317 // 'void *ptheread_getspecific(pthread_key)'. So even thought the 00318 // parameter is 'const void *', the region escapes through the call. 00319 // - funopen - sets a buffer for future IO calls. 00320 // - ObjC functions that end with "NoCopy" can free memory, of the passed 00321 // in buffer. 00322 // - Many CF containers allow objects to escape through custom 00323 // allocators/deallocators upon container construction. 00324 // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can 00325 // be deallocated by NSMapRemove. 00326 // - Any call that has a callback as one of the arguments. 00327 if (FName == "pthread_setspecific" || 00328 FName == "funopen" || 00329 FName.endswith("NoCopy") || 00330 (FName.startswith("NS") && 00331 (FName.find("Insert") != StringRef::npos)) || 00332 Call.isCFCGAllowingEscape(FName) || 00333 Call.hasNonZeroCallbackArg()) 00334 return; 00335 } 00336 00337 for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { 00338 if (FDecl && Idx < FDecl->getNumParams()) { 00339 if (isPointerToConst(FDecl->getParamDecl(Idx))) 00340 PreserveArgs.insert(Idx); 00341 } 00342 } 00343 return; 00344 } 00345 00346 if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { 00347 assert(MDecl->param_size() <= Call.getNumArgs()); 00348 unsigned Idx = 0; 00349 00350 if (Call.hasNonZeroCallbackArg()) 00351 return; 00352 00353 for (clang::ObjCMethodDecl::param_const_iterator 00354 I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { 00355 if (isPointerToConst(*I)) 00356 PreserveArgs.insert(Idx); 00357 } 00358 return; 00359 } 00360 } 00361 00362 ProgramStateRef 00363 ExprEngine::invalidateArguments(ProgramStateRef State, 00364 const CallOrObjCMessage &Call, 00365 const LocationContext *LC) { 00366 SmallVector<const MemRegion *, 8> RegionsToInvalidate; 00367 00368 if (Call.isObjCMessage()) { 00369 // Invalidate all instance variables of the receiver of an ObjC message. 00370 // FIXME: We should be able to do better with inter-procedural analysis. 00371 if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion()) 00372 RegionsToInvalidate.push_back(MR); 00373 00374 } else if (Call.isCXXCall()) { 00375 // Invalidate all instance variables for the callee of a C++ method call. 00376 // FIXME: We should be able to do better with inter-procedural analysis. 00377 // FIXME: We can probably do better for const versus non-const methods. 00378 if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion()) 00379 RegionsToInvalidate.push_back(Callee); 00380 00381 } else if (Call.isFunctionCall()) { 00382 // Block calls invalidate all captured-by-reference values. 00383 SVal CalleeVal = Call.getFunctionCallee(); 00384 if (const MemRegion *Callee = CalleeVal.getAsRegion()) { 00385 if (isa<BlockDataRegion>(Callee)) 00386 RegionsToInvalidate.push_back(Callee); 00387 } 00388 } 00389 00390 // Indexes of arguments whose values will be preserved by the call. 00391 llvm::SmallSet<unsigned, 1> PreserveArgs; 00392 findPtrToConstParams(PreserveArgs, Call); 00393 00394 for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { 00395 if (PreserveArgs.count(idx)) 00396 continue; 00397 00398 SVal V = Call.getArgSVal(idx); 00399 00400 // If we are passing a location wrapped as an integer, unwrap it and 00401 // invalidate the values referred by the location. 00402 if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V)) 00403 V = Wrapped->getLoc(); 00404 else if (!isa<Loc>(V)) 00405 continue; 00406 00407 if (const MemRegion *R = V.getAsRegion()) { 00408 // Invalidate the value of the variable passed by reference. 00409 00410 // Are we dealing with an ElementRegion? If the element type is 00411 // a basic integer type (e.g., char, int) and the underlying region 00412 // is a variable region then strip off the ElementRegion. 00413 // FIXME: We really need to think about this for the general case 00414 // as sometimes we are reasoning about arrays and other times 00415 // about (char*), etc., is just a form of passing raw bytes. 00416 // e.g., void *p = alloca(); foo((char*)p); 00417 if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 00418 // Checking for 'integral type' is probably too promiscuous, but 00419 // we'll leave it in for now until we have a systematic way of 00420 // handling all of these cases. Eventually we need to come up 00421 // with an interface to StoreManager so that this logic can be 00422 // appropriately delegated to the respective StoreManagers while 00423 // still allowing us to do checker-specific logic (e.g., 00424 // invalidating reference counts), probably via callbacks. 00425 if (ER->getElementType()->isIntegralOrEnumerationType()) { 00426 const MemRegion *superReg = ER->getSuperRegion(); 00427 if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || 00428 isa<ObjCIvarRegion>(superReg)) 00429 R = cast<TypedRegion>(superReg); 00430 } 00431 // FIXME: What about layers of ElementRegions? 00432 } 00433 00434 // Mark this region for invalidation. We batch invalidate regions 00435 // below for efficiency. 00436 RegionsToInvalidate.push_back(R); 00437 } else { 00438 // Nuke all other arguments passed by reference. 00439 // FIXME: is this necessary or correct? This handles the non-Region 00440 // cases. Is it ever valid to store to these? 00441 State = State->unbindLoc(cast<Loc>(V)); 00442 } 00443 } 00444 00445 // Invalidate designated regions using the batch invalidation API. 00446 00447 // FIXME: We can have collisions on the conjured symbol if the 00448 // expression *I also creates conjured symbols. We probably want 00449 // to identify conjured symbols by an expression pair: the enclosing 00450 // expression (the context) and the expression itself. This should 00451 // disambiguate conjured symbols. 00452 unsigned Count = currentBuilderContext->getCurrentBlockCount(); 00453 StoreManager::InvalidatedSymbols IS; 00454 00455 // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate 00456 // global variables. 00457 return State->invalidateRegions(RegionsToInvalidate, 00458 Call.getOriginExpr(), Count, LC, 00459 &IS, &Call); 00460 00461 } 00462 00463 static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N, 00464 const CallExpr *CE) { 00465 void *ReplayState = N->getState()->get<ReplayWithoutInlining>(); 00466 if (!ReplayState) 00467 return 0; 00468 const CallExpr *ReplayCE = reinterpret_cast<const CallExpr*>(ReplayState); 00469 if (CE == ReplayCE) { 00470 return N->getState()->remove<ReplayWithoutInlining>(); 00471 } 00472 return 0; 00473 } 00474 00475 void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, 00476 ExplodedNodeSet &dst) { 00477 // Perform the previsit of the CallExpr. 00478 ExplodedNodeSet dstPreVisit; 00479 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); 00480 00481 // Now evaluate the call itself. 00482 class DefaultEval : public GraphExpander { 00483 ExprEngine &Eng; 00484 const CallExpr *CE; 00485 public: 00486 00487 DefaultEval(ExprEngine &eng, const CallExpr *ce) 00488 : Eng(eng), CE(ce) {} 00489 virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { 00490 00491 ProgramStateRef state = getReplayWithoutInliningState(Pred, CE); 00492 00493 // First, try to inline the call. 00494 if (state == 0 && Eng.InlineCall(Dst, CE, Pred)) 00495 return; 00496 00497 // First handle the return value. 00498 StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext); 00499 00500 // Get the callee. 00501 const Expr *Callee = CE->getCallee()->IgnoreParens(); 00502 if (state == 0) 00503 state = Pred->getState(); 00504 SVal L = state->getSVal(Callee, Pred->getLocationContext()); 00505 00506 // Figure out the result type. We do this dance to handle references. 00507 QualType ResultTy; 00508 if (const FunctionDecl *FD = L.getAsFunctionDecl()) 00509 ResultTy = FD->getResultType(); 00510 else 00511 ResultTy = CE->getType(); 00512 00513 if (CE->isGLValue()) 00514 ResultTy = Eng.getContext().getPointerType(ResultTy); 00515 00516 // Conjure a symbol value to use as the result. 00517 SValBuilder &SVB = Eng.getSValBuilder(); 00518 unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount(); 00519 const LocationContext *LCtx = Pred->getLocationContext(); 00520 SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count); 00521 00522 // Generate a new state with the return value set. 00523 state = state->BindExpr(CE, LCtx, RetVal); 00524 00525 // Invalidate the arguments. 00526 state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx), 00527 LCtx); 00528 00529 // And make the result node. 00530 Bldr.generateNode(CE, Pred, state); 00531 } 00532 }; 00533 00534 // Finally, evaluate the function call. We try each of the checkers 00535 // to see if the can evaluate the function call. 00536 ExplodedNodeSet dstCallEvaluated; 00537 DefaultEval defEval(*this, CE); 00538 getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, 00539 dstPreVisit, 00540 CE, *this, &defEval); 00541 00542 // Finally, perform the post-condition check of the CallExpr and store 00543 // the created nodes in 'Dst'. 00544 getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, 00545 *this); 00546 } 00547 00548 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, 00549 ExplodedNodeSet &Dst) { 00550 00551 ExplodedNodeSet dstPreVisit; 00552 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); 00553 00554 StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); 00555 00556 if (RS->getRetValue()) { 00557 for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), 00558 ei = dstPreVisit.end(); it != ei; ++it) { 00559 B.generateNode(RS, *it, (*it)->getState()); 00560 } 00561 } 00562 }