diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporter.cpp | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 17 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CoreEngine.cpp | 13 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 5 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 125 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 147 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 11 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/SymbolManager.cpp | 7 |
8 files changed, 220 insertions, 115 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index a2642120b7..4330d2ed47 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -427,7 +427,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, ProgramPoint P = N->getLocation(); - if (const CallExit *CE = dyn_cast<CallExit>(&P)) { + if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) { PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SMgr); PD.getActivePath().push_front(C); @@ -440,7 +440,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PD.popActivePath(); // The current active path should never be empty. Either we // just added a bunch of stuff to the top-level path, or - // we have a previous CallExit. If the front of the active + // we have a previous CallExitEnd. If the front of the active // path is not a PathDiagnosticCallPiece, it means that the // path terminated within a function call. We must then take the // current contents of the active path and place it within @@ -1066,10 +1066,10 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, ProgramPoint P = N->getLocation(); do { - if (const CallExit *CE = dyn_cast<CallExit>(&P)) { + if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) { const StackFrameContext *LCtx = CE->getLocationContext()->getCurrentStackFrame(); - PathDiagnosticLocation Loc(LCtx->getCallSite(), + PathDiagnosticLocation Loc(CE->getStmt(), PDB.getSourceManager(), LCtx); EB.addEdge(Loc, true); @@ -1099,7 +1099,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, // The current active path should never be empty. Either we // just added a bunch of stuff to the top-level path, or - // we have a previous CallExit. If the front of the active + // we have a previous CallExitEnd. If the front of the active // path is not a PathDiagnosticCallPiece, it means that the // path terminated within a function call. We must then take the // current contents of the active path and place it within diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index 0bcc343fba..8a6ea1d0f8 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -381,21 +381,25 @@ namespace { SymbolReaper &SR; const Stmt *S; ExprEngine &Eng; + ProgramPoint::Kind ProgarmPointKind; CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } CheckersTy::const_iterator checkers_end() { return Checkers.end(); } CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, - const Stmt *s, ExprEngine &eng) - : Checkers(checkers), SR(sr), S(s), Eng(eng) { } + const Stmt *s, ExprEngine &eng, + ProgramPoint::Kind K) + : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) { } void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, NodeBuilder &Bldr, ExplodedNode *Pred) { - ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind; - const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, Pred->getLocationContext(), checkFn.Checker); CheckerContext C(Bldr, Eng, Pred, L); + // Note, do not pass the statement to the checkers without letting them + // differentiate if we ran remove dead bindings before or after the + // statement. checkFn(SR, C); } }; @@ -406,8 +410,9 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SymbolReaper &SymReaper, const Stmt *S, - ExprEngine &Eng) { - CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng); + ExprEngine &Eng, + ProgramPoint::Kind K) { + CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); expandGraphWithCheckers(C, Dst, Src); } diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index ca662c7992..c9de20e500 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -248,7 +248,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, break; } - case ProgramPoint::CallExitKind: + case ProgramPoint::CallExitBeginKind: SubEng.processCallExit(Pred); break; @@ -531,14 +531,14 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, WList->enqueue(Succ, Block, Idx+1); } -ExplodedNode *CoreEngine::generateCallExitNode(ExplodedNode *N) { - // Create a CallExit node and enqueue it. +ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) { + // Create a CallExitBegin node and enqueue it. const StackFrameContext *LocCtx = cast<StackFrameContext>(N->getLocationContext()); const Stmt *CE = LocCtx->getCallSite(); // Use the the callee location context. - CallExit Loc(CE, LocCtx); + CallExitBegin Loc(CE, LocCtx); bool isNew; ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew); @@ -565,12 +565,13 @@ void CoreEngine::enqueue(ExplodedNodeSet &Set, 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 we are in an inlined call, generate CallExitBegin node. if (N->getLocationContext()->getParent()) { - N = generateCallExitNode(N); + N = generateCallExitBeginNode(N); if (N) WList->enqueue(N); } else { + // TODO: We should run remove dead bindings here. G->addEndOfPath(N); NumPathsExplored++; } diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 0dcbe1ff4a..e433c353c1 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -57,7 +57,7 @@ ExplodedGraph::~ExplodedGraph() {} //===----------------------------------------------------------------------===// bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { - // Reclaimn all nodes that match *all* the following criteria: + // Reclaim all nodes that match *all* the following criteria: // // (1) 1 predecessor (that has one successor) // (2) 1 successor (that has one predecessor) @@ -83,7 +83,8 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // Condition 3. ProgramPoint progPoint = node->getLocation(); if (!isa<PostStmt>(progPoint) || - (isa<CallEnter>(progPoint) || isa<CallExit>(progPoint))) + (isa<CallEnter>(progPoint) || + isa<CallExitBegin>(progPoint) || isa<CallExitEnd>(progPoint))) return false; // Condition 4. diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index abc6316538..1fd4dcf712 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -42,8 +42,6 @@ using llvm::APSInt; STATISTIC(NumRemoveDeadBindings, "The # of times RemoveDeadBindings is called"); -STATISTIC(NumRemoveDeadBindingsSkipped, - "The # of times RemoveDeadBindings is skipped"); STATISTIC(NumMaxBlockCountReached, "The # of aborted paths due to reaching the maximum block count in " "a top level function"); @@ -231,6 +229,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred); return; } + currentBuilderContext = 0; } static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, @@ -260,62 +259,47 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, return !PM.isConsumedExpr(cast<Expr>(S.getStmt())); } -void ExprEngine::ProcessStmt(const CFGStmt S, - ExplodedNode *Pred) { - // Reclaim any unnecessary nodes in the ExplodedGraph. - G.reclaimRecentlyAllocatedNodes(); - - currentStmt = S.getStmt(); - PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - currentStmt->getLocStart(), - "Error evaluating statement"); - - EntryNode = Pred; - - ProgramStateRef EntryState = EntryNode->getState(); - CleanedState = EntryState; - - // Create the cleaned state. - const LocationContext *LC = EntryNode->getLocationContext(); - SymbolReaper SymReaper(LC, currentStmt, SymMgr, getStoreManager()); - - if (shouldRemoveDeadBindings(AMgr, S, Pred, LC)) { - NumRemoveDeadBindings++; - getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); - - const StackFrameContext *SFC = LC->getCurrentStackFrame(); - - // Create a state in which dead bindings are removed from the environment - // and the store. TODO: The function should just return new env and store, - // not a new state. - CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper); - } else { - NumRemoveDeadBindingsSkipped++; - } +void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, + const Stmt *ReferenceStmt, + const LocationContext *LC, + const Stmt *DiagnosticStmt, + ProgramPoint::Kind K) { + assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || + ReferenceStmt == 0) && "PreStmt is not generally supported by " + "the SymbolReaper yet"); + NumRemoveDeadBindings++; + CleanedState = Pred->getState(); + SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager()); + + getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); + + // Create a state in which dead bindings are removed from the environment + // and the store. TODO: The function should just return new env and store, + // not a new state. + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper); // Process any special transfer function for dead symbols. - ExplodedNodeSet Tmp; // A tag to track convenience transitions, which can be removed at cleanup. static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node"); - if (!SymReaper.hasDeadSymbols()) { // Generate a CleanedNode that has the environment and store cleaned // up. Since no symbols are dead, we can optimize and not clean out // the constraint manager. - StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); - Bldr.generateNode(currentStmt, EntryNode, CleanedState, false, &cleanupTag); + StmtNodeBuilder Bldr(Pred, Out, *currentBuilderContext); + Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, false, &cleanupTag,K); } else { // Call checkers with the non-cleaned state so that they could query the // values of the soon to be dead symbols. ExplodedNodeSet CheckedSet; - getCheckerManager().runCheckersForDeadSymbols(CheckedSet, EntryNode, - SymReaper, currentStmt, *this); + getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper, + DiagnosticStmt, *this, K); // For each node in CheckedSet, generate CleanedNodes that have the // environment, the store, and the constraints cleaned up but have the // user-supplied states as the predecessors. - StmtNodeBuilder Bldr(CheckedSet, Tmp, *currentBuilderContext); + StmtNodeBuilder Bldr(CheckedSet, Out, *currentBuilderContext); for (ExplodedNodeSet::const_iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { ProgramStateRef CheckerState = (*I)->getState(); @@ -324,10 +308,10 @@ void ExprEngine::ProcessStmt(const CFGStmt S, CheckerState = getConstraintManager().removeDeadBindings(CheckerState, SymReaper); - assert(StateMgr.haveEqualEnvironments(CheckerState, EntryState) && + assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && "Checkers are not allowed to modify the Environment as a part of " "checkDeadSymbols processing."); - assert(StateMgr.haveEqualStores(CheckerState, EntryState) && + assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) && "Checkers are not allowed to modify the Store as a part of " "checkDeadSymbols processing."); @@ -335,13 +319,35 @@ void ExprEngine::ProcessStmt(const CFGStmt S, // generate a transition to that state. ProgramStateRef CleanedCheckerSt = StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); - Bldr.generateNode(currentStmt, *I, CleanedCheckerSt, false, &cleanupTag, - ProgramPoint::PostPurgeDeadSymbolsKind); + Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, false, + &cleanupTag, K); } } +} + +void ExprEngine::ProcessStmt(const CFGStmt S, + ExplodedNode *Pred) { + // Reclaim any unnecessary nodes in the ExplodedGraph. + G.reclaimRecentlyAllocatedNodes(); + + currentStmt = S.getStmt(); + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + currentStmt->getLocStart(), + "Error evaluating statement"); + // Remove dead bindings and symbols. + EntryNode = Pred; + ExplodedNodeSet CleanedStates; + if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){ + removeDead(EntryNode, CleanedStates, currentStmt, + Pred->getLocationContext(), currentStmt); + } else + CleanedStates.Add(EntryNode); + + // Visit the statement. ExplodedNodeSet Dst; - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + for (ExplodedNodeSet::iterator I = CleanedStates.begin(), + E = CleanedStates.end(); I != E; ++I) { ExplodedNodeSet DstI; // Visit the statement. Visit(currentStmt, *I, DstI); @@ -994,7 +1000,7 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, continue; // We reached the caller. Find the node right before we started // processing the CallExpr. - if (isa<PostPurgeDeadSymbols>(L)) + if (L.isPurgeKind()) continue; if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L)) if (SP->getStmt() == CalleeSF->getCallSite()) @@ -1861,10 +1867,17 @@ struct DOTGraphTraits<ExplodedNode*> : ProgramPoint Loc = N->getLocation(); switch (Loc.getKind()) { - case ProgramPoint::BlockEntranceKind: + case ProgramPoint::BlockEntranceKind: { Out << "Block Entrance: B" << cast<BlockEntrance>(Loc).getBlock()->getBlockID(); + if (const NamedDecl *ND = + dyn_cast<NamedDecl>(Loc.getLocationContext()->getDecl())) { + Out << " ("; + ND->printName(Out); + Out << ")"; + } break; + } case ProgramPoint::BlockExitKind: assert (false); @@ -1874,8 +1887,20 @@ struct DOTGraphTraits<ExplodedNode*> : Out << "CallEnter"; break; - case ProgramPoint::CallExitKind: - Out << "CallExit"; + case ProgramPoint::CallExitBeginKind: + Out << "CallExitBegin"; + break; + + case ProgramPoint::CallExitEndKind: + Out << "CallExitEnd"; + break; + + case ProgramPoint::PostStmtPurgeDeadSymbolsKind: + Out << "PostStmtPurgeDeadSymbols"; + break; + + case ProgramPoint::PreStmtPurgeDeadSymbolsKind: + Out << "PreStmtPurgeDeadSymbols"; break; case ProgramPoint::EpsilonKind: diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index b9f4e153d7..4d0da06427 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -51,71 +51,140 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { Engine.getWorkList()->enqueue(Node); } -static const ReturnStmt *getReturnStmt(const ExplodedNode *Node) { +// Find the last statement on the path to the exploded node and the +// corresponding Block. +static std::pair<const Stmt*, + const CFGBlock*> getLastStmt(const ExplodedNode *Node) { + const Stmt *S = 0; + const CFGBlock *Blk = 0; + const StackFrameContext *SF = + Node->getLocation().getLocationContext()->getCurrentStackFrame(); while (Node) { const ProgramPoint &PP = Node->getLocation(); - // Skip any BlockEdges. - if (isa<BlockEdge>(PP) || isa<CallExit>(PP)) { + // Skip any BlockEdges, empty blocks, and the CallExitBegin node. + if (isa<BlockEdge>(PP) || isa<CallExitBegin>(PP) || isa<BlockEntrance>(PP)){ assert(Node->pred_size() == 1); Node = *Node->pred_begin(); continue; - } + } + // If we reached the CallEnter, the function has no statements. + if (isa<CallEnter>(PP)) + break; if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { - const Stmt *S = SP->getStmt(); - return dyn_cast<ReturnStmt>(S); + S = SP->getStmt(); + // Now, get the enclosing basic block. + while (Node && Node->pred_size() >=1 ) { + const ProgramPoint &PP = Node->getLocation(); + if (isa<BlockEdge>(PP) && + (PP.getLocationContext()->getCurrentStackFrame() == SF)) { + BlockEdge &EPP = cast<BlockEdge>(PP); + Blk = EPP.getDst(); + break; + } + Node = *Node->pred_begin(); + } + break; } break; } - return 0; + return std::pair<const Stmt*, const CFGBlock*>(S, Blk); } -void ExprEngine::processCallExit(ExplodedNode *Pred) { - ProgramStateRef state = Pred->getState(); - const StackFrameContext *calleeCtx = - Pred->getLocationContext()->getCurrentStackFrame(); +/// The call exit is simulated with a sequence of nodes, which occur between +/// CallExitBegin and CallExitEnd. The following operations occur between the +/// two program points: +/// 1. CallExitBegin (triggers the start of call exit sequence) +/// 2. Bind the return value +/// 3. Run Remove dead bindings to clean up the dead symbols from the callee. +/// 4. CallExitEnd (switch to the caller context) +/// 5. PostStmt<CallExpr> +void ExprEngine::processCallExit(ExplodedNode *CEBNode) { + // Step 1 CEBNode was generated before the call. + + const StackFrameContext *calleeCtx = + CEBNode->getLocationContext()->getCurrentStackFrame(); const LocationContext *callerCtx = calleeCtx->getParent(); const Stmt *CE = calleeCtx->getCallSite(); - + ProgramStateRef state = CEBNode->getState(); + // Find the last statement in the function and the corresponding basic block. + const Stmt *LastSt = 0; + const CFGBlock *Blk = 0; + llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); + + // Step 2: generate node with binded return value: CEBNode -> BindedRetNode. + // If the callee returns an expression, bind its value to CallExpr. - if (const ReturnStmt *RS = getReturnStmt(Pred)) { - const LocationContext *LCtx = Pred->getLocationContext(); + if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { + const LocationContext *LCtx = CEBNode->getLocationContext(); SVal V = state->getSVal(RS, LCtx); state = state->BindExpr(CE, callerCtx, V); } - + // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { const CXXThisRegion *ThisR = - getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); - + getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); + SVal ThisV = state->getSVal(ThisR); // Always bind the region to the CXXConstructExpr. - state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV); + state = state->BindExpr(CCE, CEBNode->getLocationContext(), ThisV); } - - static SimpleProgramPointTag returnTag("ExprEngine : Call Return"); - PostStmt Loc(CE, callerCtx, &returnTag); + + static SimpleProgramPointTag retValBindTag("ExprEngine : Bind Return Value"); + PostStmt Loc(LastSt, calleeCtx, &retValBindTag); bool isNew; - ExplodedNode *N = G.getNode(Loc, state, false, &isNew); - N->addPredecessor(Pred, G); + ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); + BindedRetNode->addPredecessor(CEBNode, G); if (!isNew) return; - - // Perform the post-condition check of the CallExpr. - ExplodedNodeSet Dst; - NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), N); - SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext, - &Ctx); - SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); - - getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this, - /* wasInlined */ true); - - // Enqueue the next element in the block. - for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { - Engine.getWorkList()->enqueue(*I, - calleeCtx->getCallSiteBlock(), - calleeCtx->getIndex()+1); + + // Step 3: BindedRetNode -> CleanedNodes + // If we can find a statement and a block in the inlined function, run remove + // dead bindings before returning from the call. This is important to ensure + // that we report the issues such as leaks in the stack contexts in which + // they occurred. + ExplodedNodeSet CleanedNodes; + if (LastSt && Blk) { + NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); + currentBuilderContext = &Ctx; + // Here, we call the Symbol Reaper with 0 statement and caller location + // context, telling it to clean up everything in the callee's context + // (and it's children). We use LastStmt as a diagnostic statement, which + // which the PreStmtPurge Dead point will be associated. + removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt, + ProgramPoint::PostStmtPurgeDeadSymbolsKind); + currentBuilderContext = 0; + } + + for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), + E = CleanedNodes.end(); I != E; ++I) { + + // Step 4: Generate the CallExit and leave the callee's context. + // CleanedNodes -> CEENode + CallExitEnd Loc(CE, callerCtx); + bool isNew; + ExplodedNode *CEENode = G.getNode(Loc, (*I)->getState(), false, &isNew); + CEENode->addPredecessor(*I, G); + if (!isNew) + return; + + // Step 5: Perform the post-condition check of the CallExpr and enqueue the + // result onto the work list. + // CEENode -> Dst -> WorkList + ExplodedNodeSet Dst; + NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); + SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext, + &Ctx); + SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); + + getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true); + + // Enqueue the next element in the block. + for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); + PSI != PSE; ++PSI) { + Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), + calleeCtx->getIndex()+1); + } } } diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 01dd965ac5..a1e662f129 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -510,9 +510,9 @@ static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N, PathDiagnosticCallPiece * PathDiagnosticCallPiece::construct(const ExplodedNode *N, - const CallExit &CE, + const CallExitEnd &CE, const SourceManager &SM) { - const Decl *caller = CE.getLocationContext()->getParent()->getDecl(); + const Decl *caller = CE.getLocationContext()->getDecl(); PathDiagnosticLocation pos = getLastStmtLoc(N, SM); return new PathDiagnosticCallPiece(caller, pos); } @@ -667,16 +667,13 @@ StackHintGenerator::~StackHintGenerator() {} std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ ProgramPoint P = N->getLocation(); - const CallExit *CExit = dyn_cast<CallExit>(&P); - assert(CExit && "Stack Hints should be constructed at CallExit points."); + const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); + assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt()); if (!CE) return ""; - // Get the successor node to make sure the return statement is evaluated and - // CE is set to the result value. - N = *N->succ_begin(); if (!N) return getMessageForSymbolNotFound(); diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index adefb5858e..5fee9afc08 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -501,6 +501,9 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { return false; return true; } + // If no statement is provided, everything is this and parent contexts is live. + if (!Loc) + return true; return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal); } @@ -510,6 +513,10 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); if (VarContext == CurrentContext) { + // If no statemetnt is provided, everything is live. + if (!Loc) + return true; + if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl())) return true; |