Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 1 | //=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines ExprEngine's support for calls and returns. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 14 | #define DEBUG_TYPE "ExprEngine" |
| 15 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 16 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 17 | #include "clang/AST/CXXInheritance.h" |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 18 | #include "clang/AST/DeclCXX.h" |
Jordan Rose | 6fe4dfb | 2012-08-27 18:39:22 +0000 | [diff] [blame] | 19 | #include "clang/AST/ParentMap.h" |
Chandler Carruth | 55fc873 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 20 | #include "clang/Analysis/Analyses/LiveVariables.h" |
| 21 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
| 22 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
Benjamin Kramer | 4a5f724 | 2012-04-01 19:30:51 +0000 | [diff] [blame] | 23 | #include "llvm/ADT/SmallSet.h" |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 24 | #include "llvm/ADT/Statistic.h" |
Benjamin Kramer | 4a5f724 | 2012-04-01 19:30:51 +0000 | [diff] [blame] | 25 | #include "llvm/Support/SaveAndRestore.h" |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 26 | |
| 27 | using namespace clang; |
| 28 | using namespace ento; |
| 29 | |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 30 | STATISTIC(NumOfDynamicDispatchPathSplits, |
| 31 | "The # of times we split the path due to imprecise dynamic dispatch info"); |
| 32 | |
Anna Zaks | 210f5a2 | 2012-08-27 18:38:32 +0000 | [diff] [blame] | 33 | STATISTIC(NumInlinedCalls, |
| 34 | "The # of times we inlined a call"); |
| 35 | |
Anna Zaks | 7959671 | 2012-12-17 20:08:51 +0000 | [diff] [blame] | 36 | STATISTIC(NumReachedInlineCountMax, |
| 37 | "The # of times we reached inline count maximum"); |
| 38 | |
Ted Kremenek | 3070e13 | 2012-01-07 01:03:17 +0000 | [diff] [blame] | 39 | void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { |
| 40 | // Get the entry block in the CFG of the callee. |
Ted Kremenek | 0849ade | 2012-01-12 19:25:46 +0000 | [diff] [blame] | 41 | const StackFrameContext *calleeCtx = CE.getCalleeContext(); |
| 42 | const CFG *CalleeCFG = calleeCtx->getCFG(); |
Ted Kremenek | 3070e13 | 2012-01-07 01:03:17 +0000 | [diff] [blame] | 43 | const CFGBlock *Entry = &(CalleeCFG->getEntry()); |
| 44 | |
| 45 | // Validate the CFG. |
| 46 | assert(Entry->empty()); |
| 47 | assert(Entry->succ_size() == 1); |
| 48 | |
| 49 | // Get the solitary sucessor. |
| 50 | const CFGBlock *Succ = *(Entry->succ_begin()); |
| 51 | |
| 52 | // Construct an edge representing the starting location in the callee. |
Ted Kremenek | 0849ade | 2012-01-12 19:25:46 +0000 | [diff] [blame] | 53 | BlockEdge Loc(Entry, Succ, calleeCtx); |
Ted Kremenek | 3070e13 | 2012-01-07 01:03:17 +0000 | [diff] [blame] | 54 | |
Jordan Rose | e54cfc7 | 2012-07-10 22:07:57 +0000 | [diff] [blame] | 55 | ProgramStateRef state = Pred->getState(); |
Ted Kremenek | 3070e13 | 2012-01-07 01:03:17 +0000 | [diff] [blame] | 56 | |
| 57 | // Construct a new node and add it to the worklist. |
| 58 | bool isNew; |
| 59 | ExplodedNode *Node = G.getNode(Loc, state, false, &isNew); |
| 60 | Node->addPredecessor(Pred, G); |
| 61 | if (isNew) |
| 62 | Engine.getWorkList()->enqueue(Node); |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 63 | } |
| 64 | |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 65 | // Find the last statement on the path to the exploded node and the |
| 66 | // corresponding Block. |
| 67 | static std::pair<const Stmt*, |
| 68 | const CFGBlock*> getLastStmt(const ExplodedNode *Node) { |
| 69 | const Stmt *S = 0; |
Jordan Rose | 4ecca28 | 2012-12-06 18:58:15 +0000 | [diff] [blame] | 70 | const CFGBlock *Blk = 0; |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 71 | const StackFrameContext *SF = |
| 72 | Node->getLocation().getLocationContext()->getCurrentStackFrame(); |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 73 | |
Jordan Rose | 632e502 | 2012-08-28 20:52:13 +0000 | [diff] [blame] | 74 | // Back up through the ExplodedGraph until we reach a statement node in this |
| 75 | // stack frame. |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 76 | while (Node) { |
| 77 | const ProgramPoint &PP = Node->getLocation(); |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 78 | |
Jordan Rose | 632e502 | 2012-08-28 20:52:13 +0000 | [diff] [blame] | 79 | if (PP.getLocationContext()->getCurrentStackFrame() == SF) { |
| 80 | if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { |
| 81 | S = SP->getStmt(); |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 82 | break; |
Jordan Rose | 632e502 | 2012-08-28 20:52:13 +0000 | [diff] [blame] | 83 | } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) { |
| 84 | S = CEE->getCalleeContext()->getCallSite(); |
| 85 | if (S) |
| 86 | break; |
| 87 | |
| 88 | // If there is no statement, this is an implicitly-generated call. |
| 89 | // We'll walk backwards over it and then continue the loop to find |
| 90 | // an actual statement. |
| 91 | const CallEnter *CE; |
| 92 | do { |
| 93 | Node = Node->getFirstPred(); |
| 94 | CE = Node->getLocationAs<CallEnter>(); |
| 95 | } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext()); |
| 96 | |
| 97 | // Continue searching the graph. |
Jordan Rose | 4ecca28 | 2012-12-06 18:58:15 +0000 | [diff] [blame] | 98 | } else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&PP)) { |
| 99 | Blk = BE->getSrc(); |
Jordan Rose | 632e502 | 2012-08-28 20:52:13 +0000 | [diff] [blame] | 100 | } |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 101 | } else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) { |
| 102 | // If we reached the CallEnter for this function, it has no statements. |
| 103 | if (CE->getCalleeContext() == SF) |
| 104 | break; |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 105 | } |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 106 | |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 107 | if (Node->pred_empty()) |
NAKAMURA Takumi | 0a591c2 | 2012-11-03 13:59:36 +0000 | [diff] [blame] | 108 | return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0); |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 109 | |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 110 | Node = *Node->pred_begin(); |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 111 | } |
Jordan Rose | 888c90a | 2012-07-26 20:04:13 +0000 | [diff] [blame] | 112 | |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 113 | return std::pair<const Stmt*, const CFGBlock*>(S, Blk); |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 114 | } |
| 115 | |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 116 | /// Adjusts a return value when the called function's return type does not |
| 117 | /// match the caller's expression type. This can happen when a dynamic call |
| 118 | /// is devirtualized, and the overridding method has a covariant (more specific) |
| 119 | /// return type than the parent's method. For C++ objects, this means we need |
| 120 | /// to add base casts. |
| 121 | static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy, |
| 122 | StoreManager &StoreMgr) { |
| 123 | // For now, the only adjustments we handle apply only to locations. |
| 124 | if (!isa<Loc>(V)) |
| 125 | return V; |
| 126 | |
| 127 | // If the types already match, don't do any unnecessary work. |
Anna Zaks | e7ad14e | 2012-11-12 22:06:24 +0000 | [diff] [blame] | 128 | ExpectedTy = ExpectedTy.getCanonicalType(); |
| 129 | ActualTy = ActualTy.getCanonicalType(); |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 130 | if (ExpectedTy == ActualTy) |
| 131 | return V; |
| 132 | |
| 133 | // No adjustment is needed between Objective-C pointer types. |
| 134 | if (ExpectedTy->isObjCObjectPointerType() && |
| 135 | ActualTy->isObjCObjectPointerType()) |
| 136 | return V; |
| 137 | |
| 138 | // C++ object pointers may need "derived-to-base" casts. |
| 139 | const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl(); |
| 140 | const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl(); |
| 141 | if (ExpectedClass && ActualClass) { |
| 142 | CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, |
| 143 | /*DetectVirtual=*/false); |
| 144 | if (ActualClass->isDerivedFrom(ExpectedClass, Paths) && |
| 145 | !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) { |
| 146 | return StoreMgr.evalDerivedToBase(V, Paths.front()); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | // Unfortunately, Objective-C does not enforce that overridden methods have |
| 151 | // covariant return types, so we can't assert that that never happens. |
| 152 | // Be safe and return UnknownVal(). |
| 153 | return UnknownVal(); |
| 154 | } |
| 155 | |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 156 | void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC, |
| 157 | ExplodedNode *Pred, |
| 158 | ExplodedNodeSet &Dst) { |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 159 | // Find the last statement in the function and the corresponding basic block. |
| 160 | const Stmt *LastSt = 0; |
| 161 | const CFGBlock *Blk = 0; |
| 162 | llvm::tie(LastSt, Blk) = getLastStmt(Pred); |
| 163 | if (!Blk || !LastSt) { |
Jordan Rose | 84c4845 | 2012-11-15 19:11:27 +0000 | [diff] [blame] | 164 | Dst.Add(Pred); |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 165 | return; |
| 166 | } |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 167 | |
Jordan Rose | 63bc186 | 2012-11-15 19:11:43 +0000 | [diff] [blame] | 168 | // Here, we destroy the current location context. We use the current |
| 169 | // function's entire body as a diagnostic statement, with which the program |
| 170 | // point will be associated. However, we only want to use LastStmt as a |
| 171 | // reference for what to clean up if it's a ReturnStmt; otherwise, everything |
| 172 | // is dead. |
Jordan Rose | 84c4845 | 2012-11-15 19:11:27 +0000 | [diff] [blame] | 173 | SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC); |
Jordan Rose | 63bc186 | 2012-11-15 19:11:43 +0000 | [diff] [blame] | 174 | const LocationContext *LCtx = Pred->getLocationContext(); |
| 175 | removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), LCtx, |
| 176 | LCtx->getAnalysisDeclContext()->getBody(), |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 177 | ProgramPoint::PostStmtPurgeDeadSymbolsKind); |
Anna Zaks | 8501b7a | 2012-11-03 02:54:20 +0000 | [diff] [blame] | 178 | } |
| 179 | |
Anna Zaks | bae930d | 2012-11-13 00:13:44 +0000 | [diff] [blame] | 180 | static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, |
Anna Zaks | d51db49 | 2012-11-12 23:40:29 +0000 | [diff] [blame] | 181 | const StackFrameContext *calleeCtx) { |
| 182 | const Decl *RuntimeCallee = calleeCtx->getDecl(); |
| 183 | const Decl *StaticDecl = Call->getDecl(); |
Anna Zaks | bae930d | 2012-11-13 00:13:44 +0000 | [diff] [blame] | 184 | assert(RuntimeCallee); |
| 185 | if (!StaticDecl) |
| 186 | return true; |
Anna Zaks | d51db49 | 2012-11-12 23:40:29 +0000 | [diff] [blame] | 187 | return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl(); |
| 188 | } |
| 189 | |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 190 | /// The call exit is simulated with a sequence of nodes, which occur between |
| 191 | /// CallExitBegin and CallExitEnd. The following operations occur between the |
| 192 | /// two program points: |
| 193 | /// 1. CallExitBegin (triggers the start of call exit sequence) |
| 194 | /// 2. Bind the return value |
| 195 | /// 3. Run Remove dead bindings to clean up the dead symbols from the callee. |
| 196 | /// 4. CallExitEnd (switch to the caller context) |
| 197 | /// 5. PostStmt<CallExpr> |
| 198 | void ExprEngine::processCallExit(ExplodedNode *CEBNode) { |
| 199 | // Step 1 CEBNode was generated before the call. |
| 200 | |
| 201 | const StackFrameContext *calleeCtx = |
| 202 | CEBNode->getLocationContext()->getCurrentStackFrame(); |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 203 | |
| 204 | // The parent context might not be a stack frame, so make sure we |
| 205 | // look up the first enclosing stack frame. |
| 206 | const StackFrameContext *callerCtx = |
| 207 | calleeCtx->getParent()->getCurrentStackFrame(); |
| 208 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 209 | const Stmt *CE = calleeCtx->getCallSite(); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 210 | ProgramStateRef state = CEBNode->getState(); |
| 211 | // Find the last statement in the function and the corresponding basic block. |
| 212 | const Stmt *LastSt = 0; |
| 213 | const CFGBlock *Blk = 0; |
| 214 | llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); |
| 215 | |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 216 | // Generate a CallEvent /before/ cleaning the state, so that we can get the |
| 217 | // correct value for 'this' (if necessary). |
| 218 | CallEventManager &CEMgr = getStateManager().getCallEventManager(); |
| 219 | CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); |
| 220 | |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 221 | // Step 2: generate node with bound return value: CEBNode -> BindedRetNode. |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 222 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 223 | // If the callee returns an expression, bind its value to CallExpr. |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 224 | if (CE) { |
| 225 | if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { |
| 226 | const LocationContext *LCtx = CEBNode->getLocationContext(); |
| 227 | SVal V = state->getSVal(RS, LCtx); |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 228 | |
Anna Zaks | d51db49 | 2012-11-12 23:40:29 +0000 | [diff] [blame] | 229 | // Ensure that the return type matches the type of the returned Expr. |
Anna Zaks | bae930d | 2012-11-13 00:13:44 +0000 | [diff] [blame] | 230 | if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) { |
Anna Zaks | d51db49 | 2012-11-12 23:40:29 +0000 | [diff] [blame] | 231 | QualType ReturnedTy = |
| 232 | CallEvent::getDeclaredResultType(calleeCtx->getDecl()); |
Jordan Rose | 48314cf | 2012-10-03 01:08:35 +0000 | [diff] [blame] | 233 | if (!ReturnedTy.isNull()) { |
| 234 | if (const Expr *Ex = dyn_cast<Expr>(CE)) { |
| 235 | V = adjustReturnValue(V, Ex->getType(), ReturnedTy, |
| 236 | getStoreManager()); |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 241 | state = state->BindExpr(CE, callerCtx, V); |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 242 | } |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 243 | |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 244 | // Bind the constructed object value to CXXConstructExpr. |
| 245 | if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { |
| 246 | loc::MemRegionVal This = |
| 247 | svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx); |
| 248 | SVal ThisV = state->getSVal(This); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 249 | |
Jordan Rose | 33e83b6 | 2013-01-31 18:04:03 +0000 | [diff] [blame^] | 250 | // If the constructed object is a prvalue, get its bindings. |
| 251 | // Note that we have to be careful here because constructors embedded |
| 252 | // in DeclStmts are not marked as lvalues. |
| 253 | if (!CCE->isGLValue()) |
| 254 | if (const MemRegion *MR = ThisV.getAsRegion()) |
| 255 | if (isa<CXXTempObjectRegion>(MR)) |
| 256 | ThisV = state->getSVal(cast<Loc>(ThisV)); |
Jordan Rose | 0504a59 | 2012-10-01 17:51:35 +0000 | [diff] [blame] | 257 | |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 258 | state = state->BindExpr(CCE, callerCtx, ThisV); |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 259 | } |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 260 | } |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 261 | |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 262 | // Step 3: BindedRetNode -> CleanedNodes |
| 263 | // If we can find a statement and a block in the inlined function, run remove |
| 264 | // dead bindings before returning from the call. This is important to ensure |
| 265 | // that we report the issues such as leaks in the stack contexts in which |
| 266 | // they occurred. |
| 267 | ExplodedNodeSet CleanedNodes; |
Ted Kremenek | 255d4d4 | 2012-08-30 19:26:43 +0000 | [diff] [blame] | 268 | if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { |
Jordan Rose | 48b6247 | 2012-07-10 22:08:01 +0000 | [diff] [blame] | 269 | static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value"); |
| 270 | PostStmt Loc(LastSt, calleeCtx, &retValBind); |
| 271 | bool isNew; |
| 272 | ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); |
| 273 | BindedRetNode->addPredecessor(CEBNode, G); |
| 274 | if (!isNew) |
| 275 | return; |
| 276 | |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 277 | NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 278 | currBldrCtx = &Ctx; |
Jordan Rose | 84c4845 | 2012-11-15 19:11:27 +0000 | [diff] [blame] | 279 | // Here, we call the Symbol Reaper with 0 statement and callee location |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 280 | // context, telling it to clean up everything in the callee's context |
Jordan Rose | 63bc186 | 2012-11-15 19:11:43 +0000 | [diff] [blame] | 281 | // (and its children). We use the callee's function body as a diagnostic |
| 282 | // statement, with which the program point will be associated. |
| 283 | removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx, |
| 284 | calleeCtx->getAnalysisDeclContext()->getBody(), |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 285 | ProgramPoint::PostStmtPurgeDeadSymbolsKind); |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 286 | currBldrCtx = 0; |
Anna Zaks | 144e52b | 2012-06-01 23:48:40 +0000 | [diff] [blame] | 287 | } else { |
| 288 | CleanedNodes.Add(CEBNode); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 289 | } |
| 290 | |
| 291 | for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), |
| 292 | E = CleanedNodes.end(); I != E; ++I) { |
| 293 | |
| 294 | // Step 4: Generate the CallExit and leave the callee's context. |
| 295 | // CleanedNodes -> CEENode |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 296 | CallExitEnd Loc(calleeCtx, callerCtx); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 297 | bool isNew; |
Jordan Rose | 48b6247 | 2012-07-10 22:08:01 +0000 | [diff] [blame] | 298 | ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState(); |
| 299 | ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 300 | CEENode->addPredecessor(*I, G); |
| 301 | if (!isNew) |
| 302 | return; |
| 303 | |
| 304 | // Step 5: Perform the post-condition check of the CallExpr and enqueue the |
| 305 | // result onto the work list. |
| 306 | // CEENode -> Dst -> WorkList |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 307 | NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 308 | SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx, |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 309 | &Ctx); |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 310 | SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex()); |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 311 | |
Jordan Rose | 4e79fdf | 2012-08-15 20:07:17 +0000 | [diff] [blame] | 312 | CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState); |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 313 | |
| 314 | ExplodedNodeSet DstPostCall; |
Jordan Rose | 4e79fdf | 2012-08-15 20:07:17 +0000 | [diff] [blame] | 315 | getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, |
| 316 | *UpdatedCall, *this, |
| 317 | /*WasInlined=*/true); |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 318 | |
| 319 | ExplodedNodeSet Dst; |
Jordan Rose | 4e79fdf | 2012-08-15 20:07:17 +0000 | [diff] [blame] | 320 | if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { |
| 321 | getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg, |
| 322 | *this, |
| 323 | /*WasInlined=*/true); |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 324 | } else if (CE) { |
| 325 | getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE, |
Jordan Rose | 4e79fdf | 2012-08-15 20:07:17 +0000 | [diff] [blame] | 326 | *this, /*WasInlined=*/true); |
Jordan Rose | 57c0336 | 2012-07-30 23:39:47 +0000 | [diff] [blame] | 327 | } else { |
| 328 | Dst.insert(DstPostCall); |
| 329 | } |
Anna Zaks | 0b3ade8 | 2012-04-20 21:59:08 +0000 | [diff] [blame] | 330 | |
| 331 | // Enqueue the next element in the block. |
| 332 | for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); |
| 333 | PSI != PSE; ++PSI) { |
| 334 | Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), |
| 335 | calleeCtx->getIndex()+1); |
| 336 | } |
Ted Kremenek | 242384d | 2012-01-07 00:10:49 +0000 | [diff] [blame] | 337 | } |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 338 | } |
| 339 | |
Anna Zaks | 4ea9b89 | 2012-09-10 23:35:11 +0000 | [diff] [blame] | 340 | void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx, |
Anna Zaks | 7229d00 | 2012-09-10 22:37:19 +0000 | [diff] [blame] | 341 | bool &IsRecursive, unsigned &StackDepth) { |
| 342 | IsRecursive = false; |
| 343 | StackDepth = 0; |
Anna Zaks | 4ea9b89 | 2012-09-10 23:35:11 +0000 | [diff] [blame] | 344 | |
Ted Kremenek | 0849ade | 2012-01-12 19:25:46 +0000 | [diff] [blame] | 345 | while (LCtx) { |
Anna Zaks | 7229d00 | 2012-09-10 22:37:19 +0000 | [diff] [blame] | 346 | if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) { |
Anna Zaks | 4ea9b89 | 2012-09-10 23:35:11 +0000 | [diff] [blame] | 347 | const Decl *DI = SFC->getDecl(); |
| 348 | |
| 349 | // Mark recursive (and mutually recursive) functions and always count |
| 350 | // them when measuring the stack depth. |
| 351 | if (DI == D) { |
Anna Zaks | 7229d00 | 2012-09-10 22:37:19 +0000 | [diff] [blame] | 352 | IsRecursive = true; |
Anna Zaks | 4ea9b89 | 2012-09-10 23:35:11 +0000 | [diff] [blame] | 353 | ++StackDepth; |
| 354 | LCtx = LCtx->getParent(); |
| 355 | continue; |
| 356 | } |
| 357 | |
| 358 | // Do not count the small functions when determining the stack depth. |
| 359 | AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI); |
| 360 | const CFG *CalleeCFG = CalleeADC->getCFG(); |
| 361 | if (CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize()) |
| 362 | ++StackDepth; |
Anna Zaks | 7229d00 | 2012-09-10 22:37:19 +0000 | [diff] [blame] | 363 | } |
Ted Kremenek | 0849ade | 2012-01-12 19:25:46 +0000 | [diff] [blame] | 364 | LCtx = LCtx->getParent(); |
| 365 | } |
Anna Zaks | 4ea9b89 | 2012-09-10 23:35:11 +0000 | [diff] [blame] | 366 | |
Ted Kremenek | 0849ade | 2012-01-12 19:25:46 +0000 | [diff] [blame] | 367 | } |
| 368 | |
Jordan Rose | 81fb50e | 2012-09-10 21:27:35 +0000 | [diff] [blame] | 369 | static bool IsInStdNamespace(const FunctionDecl *FD) { |
| 370 | const DeclContext *DC = FD->getEnclosingNamespaceContext(); |
| 371 | const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); |
| 372 | if (!ND) |
| 373 | return false; |
| 374 | |
| 375 | while (const DeclContext *Parent = ND->getParent()) { |
| 376 | if (!isa<NamespaceDecl>(Parent)) |
| 377 | break; |
| 378 | ND = cast<NamespaceDecl>(Parent); |
| 379 | } |
| 380 | |
| 381 | return ND->getName() == "std"; |
| 382 | } |
| 383 | |
Anna Zaks | 6cc0969 | 2012-03-13 22:15:58 +0000 | [diff] [blame] | 384 | // Determine if we should inline the call. |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 385 | bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) { |
| 386 | AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D); |
Anna Zaks | 6cc0969 | 2012-03-13 22:15:58 +0000 | [diff] [blame] | 387 | const CFG *CalleeCFG = CalleeADC->getCFG(); |
| 388 | |
Ted Kremenek | 01561d1 | 2012-04-17 01:36:03 +0000 | [diff] [blame] | 389 | // It is possible that the CFG cannot be constructed. |
| 390 | // Be safe, and check if the CalleeCFG is valid. |
| 391 | if (!CalleeCFG) |
| 392 | return false; |
| 393 | |
Anna Zaks | 7229d00 | 2012-09-10 22:37:19 +0000 | [diff] [blame] | 394 | bool IsRecursive = false; |
| 395 | unsigned StackDepth = 0; |
| 396 | examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth); |
| 397 | if ((StackDepth >= AMgr.options.InlineMaxStackDepth) && |
| 398 | ((CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize()) |
| 399 | || IsRecursive)) |
Anna Zaks | 6cc0969 | 2012-03-13 22:15:58 +0000 | [diff] [blame] | 400 | return false; |
| 401 | |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 402 | if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D)) |
Anna Zaks | 3bbd8cd | 2012-03-30 05:48:10 +0000 | [diff] [blame] | 403 | return false; |
| 404 | |
Anna Zaks | 6bbe144 | 2013-01-30 19:12:36 +0000 | [diff] [blame] | 405 | if (CalleeCFG->getNumBlockIDs() > AMgr.options.getMaxInlinableSize()) |
Anna Zaks | 6cc0969 | 2012-03-13 22:15:58 +0000 | [diff] [blame] | 406 | return false; |
| 407 | |
Ted Kremenek | 10f77ad | 2012-06-22 23:55:50 +0000 | [diff] [blame] | 408 | // Do not inline variadic calls (for now). |
| 409 | if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { |
| 410 | if (BD->isVariadic()) |
| 411 | return false; |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 412 | } |
Ted Kremenek | 10f77ad | 2012-06-22 23:55:50 +0000 | [diff] [blame] | 413 | else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| 414 | if (FD->isVariadic()) |
| 415 | return false; |
| 416 | } |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 417 | |
Jordan Rose | 81fb50e | 2012-09-10 21:27:35 +0000 | [diff] [blame] | 418 | if (getContext().getLangOpts().CPlusPlus) { |
| 419 | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| 420 | // Conditionally allow the inlining of template functions. |
Anna Zaks | 7959671 | 2012-12-17 20:08:51 +0000 | [diff] [blame] | 421 | if (!AMgr.options.mayInlineTemplateFunctions()) |
Jordan Rose | 81fb50e | 2012-09-10 21:27:35 +0000 | [diff] [blame] | 422 | if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) |
| 423 | return false; |
| 424 | |
| 425 | // Conditionally allow the inlining of C++ standard library functions. |
Anna Zaks | 7959671 | 2012-12-17 20:08:51 +0000 | [diff] [blame] | 426 | if (!AMgr.options.mayInlineCXXStandardLibrary()) |
Jordan Rose | 81fb50e | 2012-09-10 21:27:35 +0000 | [diff] [blame] | 427 | if (getContext().getSourceManager().isInSystemHeader(FD->getLocation())) |
| 428 | if (IsInStdNamespace(FD)) |
| 429 | return false; |
| 430 | } |
| 431 | } |
| 432 | |
Ted Kremenek | d4aeb80 | 2012-07-02 20:21:52 +0000 | [diff] [blame] | 433 | // It is possible that the live variables analysis cannot be |
| 434 | // run. If so, bail out. |
| 435 | if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) |
| 436 | return false; |
| 437 | |
Anna Zaks | 7959671 | 2012-12-17 20:08:51 +0000 | [diff] [blame] | 438 | if (Engine.FunctionSummaries->getNumTimesInlined(D) > |
| 439 | AMgr.options.getMaxTimesInlineLarge() && |
| 440 | CalleeCFG->getNumBlockIDs() > 13) { |
| 441 | NumReachedInlineCountMax++; |
| 442 | return false; |
| 443 | } |
| 444 | Engine.FunctionSummaries->bumpNumTimesInlined(D); |
| 445 | |
Ted Kremenek | 10f77ad | 2012-06-22 23:55:50 +0000 | [diff] [blame] | 446 | return true; |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 447 | } |
| 448 | |
Jordan Rose | 166d502 | 2012-11-02 01:54:06 +0000 | [diff] [blame] | 449 | // The GDM component containing the dynamic dispatch bifurcation info. When |
| 450 | // the exact type of the receiver is not known, we want to explore both paths - |
| 451 | // one on which we do inline it and the other one on which we don't. This is |
| 452 | // done to ensure we do not drop coverage. |
| 453 | // This is the map from the receiver region to a bool, specifying either we |
| 454 | // consider this region's information precise or not along the given path. |
| 455 | namespace { |
| 456 | enum DynamicDispatchMode { |
| 457 | DynamicDispatchModeInlined = 1, |
| 458 | DynamicDispatchModeConservative |
| 459 | }; |
| 460 | } |
Jordan Rose | 40d8551 | 2012-11-05 16:58:00 +0000 | [diff] [blame] | 461 | REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap, |
| 462 | CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, |
| 463 | unsigned)) |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 464 | |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 465 | bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, |
| 466 | NodeBuilder &Bldr, ExplodedNode *Pred, |
| 467 | ProgramStateRef State) { |
| 468 | assert(D); |
Jordan Rose | ee158bc | 2012-07-09 16:54:49 +0000 | [diff] [blame] | 469 | |
Jordan Rose | c36b30c | 2012-07-12 00:16:25 +0000 | [diff] [blame] | 470 | const LocationContext *CurLC = Pred->getLocationContext(); |
| 471 | const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 472 | const LocationContext *ParentOfCallee = 0; |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 473 | |
Ted Kremenek | 622b6fb | 2012-10-01 18:28:19 +0000 | [diff] [blame] | 474 | AnalyzerOptions &Opts = getAnalysisManager().options; |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 475 | |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 476 | // FIXME: Refactor this check into a hypothetical CallEvent::canInline. |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 477 | switch (Call.getKind()) { |
| 478 | case CE_Function: |
Jordan Rose | 2f9c40a | 2012-07-31 18:22:40 +0000 | [diff] [blame] | 479 | break; |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 480 | case CE_CXXMember: |
Jordan Rose | e54cfc7 | 2012-07-10 22:07:57 +0000 | [diff] [blame] | 481 | case CE_CXXMemberOperator: |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 482 | if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) |
Jordan Rose | 2f9c40a | 2012-07-31 18:22:40 +0000 | [diff] [blame] | 483 | return false; |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 484 | break; |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 485 | case CE_CXXConstructor: { |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 486 | if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) |
Jordan Rose | 2f9c40a | 2012-07-31 18:22:40 +0000 | [diff] [blame] | 487 | return false; |
| 488 | |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 489 | const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); |
| 490 | |
| 491 | // FIXME: We don't handle constructors or destructors for arrays properly. |
| 492 | const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); |
| 493 | if (Target && isa<ElementRegion>(Target)) |
| 494 | return false; |
| 495 | |
Jordan Rose | 6fe4dfb | 2012-08-27 18:39:22 +0000 | [diff] [blame] | 496 | // FIXME: This is a hack. We don't use the correct region for a new |
| 497 | // expression, so if we inline the constructor its result will just be |
| 498 | // thrown away. This short-term hack is tracked in <rdar://problem/12180598> |
| 499 | // and the longer-term possible fix is discussed in PR12014. |
| 500 | const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); |
| 501 | if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr)) |
| 502 | if (isa<CXXNewExpr>(Parent)) |
| 503 | return false; |
| 504 | |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 505 | // Inlining constructors requires including initializers in the CFG. |
| 506 | const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); |
| 507 | assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); |
Jordan Rose | 9eb214a | 2012-09-01 19:15:13 +0000 | [diff] [blame] | 508 | (void)ADC; |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 509 | |
Jordan Rose | c210cb7 | 2012-08-27 17:50:07 +0000 | [diff] [blame] | 510 | // If the destructor is trivial, it's always safe to inline the constructor. |
| 511 | if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) |
| 512 | break; |
| 513 | |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 514 | // For other types, only inline constructors if destructor inlining is |
| 515 | // also enabled. |
| 516 | if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) |
Jordan Rose | c210cb7 | 2012-08-27 17:50:07 +0000 | [diff] [blame] | 517 | return false; |
| 518 | |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 519 | // FIXME: This is a hack. We don't handle temporary destructors |
| 520 | // right now, so we shouldn't inline their constructors. |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 521 | if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) |
| 522 | if (!Target || !isa<DeclRegion>(Target)) |
| 523 | return false; |
| 524 | |
| 525 | break; |
| 526 | } |
Jordan Rose | da5fc53 | 2012-07-26 20:04:00 +0000 | [diff] [blame] | 527 | case CE_CXXDestructor: { |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 528 | if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) |
Jordan Rose | 2f9c40a | 2012-07-31 18:22:40 +0000 | [diff] [blame] | 529 | return false; |
| 530 | |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 531 | // Inlining destructors requires building the CFG correctly. |
Jordan Rose | da5fc53 | 2012-07-26 20:04:00 +0000 | [diff] [blame] | 532 | const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); |
Jordan Rose | de5277f | 2012-08-31 17:06:49 +0000 | [diff] [blame] | 533 | assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); |
Jordan Rose | 9eb214a | 2012-09-01 19:15:13 +0000 | [diff] [blame] | 534 | (void)ADC; |
Jordan Rose | 3a0a9e3 | 2012-07-26 20:04:21 +0000 | [diff] [blame] | 535 | |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 536 | const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call); |
| 537 | |
Jordan Rose | e460c46 | 2012-07-26 20:04:25 +0000 | [diff] [blame] | 538 | // FIXME: We don't handle constructors or destructors for arrays properly. |
Jordan Rose | ef15831 | 2012-07-31 01:07:55 +0000 | [diff] [blame] | 539 | const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion(); |
Jordan Rose | e460c46 | 2012-07-26 20:04:25 +0000 | [diff] [blame] | 540 | if (Target && isa<ElementRegion>(Target)) |
| 541 | return false; |
| 542 | |
Jordan Rose | da5fc53 | 2012-07-26 20:04:00 +0000 | [diff] [blame] | 543 | break; |
| 544 | } |
Jordan Rose | 70cbf3c | 2012-07-02 22:21:47 +0000 | [diff] [blame] | 545 | case CE_CXXAllocator: |
| 546 | // Do not inline allocators until we model deallocators. |
| 547 | // This is unfortunate, but basically necessary for smart pointers and such. |
| 548 | return false; |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 549 | case CE_Block: { |
| 550 | const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion(); |
Jordan Rose | ee158bc | 2012-07-09 16:54:49 +0000 | [diff] [blame] | 551 | assert(BR && "If we have the block definition we should have its region"); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 552 | AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D); |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 553 | ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC, |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 554 | cast<BlockDecl>(D), |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 555 | BR); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 556 | break; |
| 557 | } |
| 558 | case CE_ObjCMessage: |
Anna Zaks | 57330ee | 2012-09-10 22:56:41 +0000 | [diff] [blame] | 559 | if (!Opts.mayInlineObjCMethod()) |
| 560 | return false; |
Anna Zaks | 73f0563 | 2013-01-24 23:15:25 +0000 | [diff] [blame] | 561 | AnalyzerOptions &Options = getAnalysisManager().options; |
Anna Zaks | bfa9ab8 | 2013-01-24 23:15:30 +0000 | [diff] [blame] | 562 | if (!(Options.getIPAMode() == IPAK_DynamicDispatch || |
| 563 | Options.getIPAMode() == IPAK_DynamicDispatchBifurcate)) |
Anna Zaks | e13056a | 2012-07-30 20:31:18 +0000 | [diff] [blame] | 564 | return false; |
Anna Zaks | 9dc5167 | 2012-07-26 00:27:51 +0000 | [diff] [blame] | 565 | break; |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 566 | } |
Jordan Rose | ee158bc | 2012-07-09 16:54:49 +0000 | [diff] [blame] | 567 | |
| 568 | if (!shouldInlineDecl(D, Pred)) |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 569 | return false; |
| 570 | |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 571 | if (!ParentOfCallee) |
| 572 | ParentOfCallee = CallerSFC; |
Anna Zaks | 8235f9c | 2012-03-02 19:05:03 +0000 | [diff] [blame] | 573 | |
Jordan Rose | 852aa0d | 2012-07-10 22:07:52 +0000 | [diff] [blame] | 574 | // This may be NULL, but that's fine. |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 575 | const Expr *CallE = Call.getOriginExpr(); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 576 | |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 577 | // Construct a new stack frame for the callee. |
| 578 | AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D); |
| 579 | const StackFrameContext *CalleeSFC = |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 580 | CalleeADC->getStackFrame(ParentOfCallee, CallE, |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 581 | currBldrCtx->getBlock(), |
| 582 | currStmtIdx); |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 583 | |
Jordan Rose | c36b30c | 2012-07-12 00:16:25 +0000 | [diff] [blame] | 584 | CallEnter Loc(CallE, CalleeSFC, CurLC); |
Jordan Rose | e54cfc7 | 2012-07-10 22:07:57 +0000 | [diff] [blame] | 585 | |
| 586 | // Construct a new state which contains the mapping from actual to |
| 587 | // formal arguments. |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 588 | State = State->enterStackFrame(Call, CalleeSFC); |
Jordan Rose | e54cfc7 | 2012-07-10 22:07:57 +0000 | [diff] [blame] | 589 | |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 590 | bool isNew; |
Jordan Rose | e54cfc7 | 2012-07-10 22:07:57 +0000 | [diff] [blame] | 591 | if (ExplodedNode *N = G.getNode(Loc, State, false, &isNew)) { |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 592 | N->addPredecessor(Pred, G); |
| 593 | if (isNew) |
| 594 | Engine.getWorkList()->enqueue(N); |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 595 | } |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 596 | |
| 597 | // If we decided to inline the call, the successor has been manually |
| 598 | // added onto the work list so remove it from the node builder. |
| 599 | Bldr.takeNodes(Pred); |
| 600 | |
Anna Zaks | 210f5a2 | 2012-08-27 18:38:32 +0000 | [diff] [blame] | 601 | NumInlinedCalls++; |
| 602 | |
Anna Zaks | fbcb3f1 | 2012-08-30 23:42:02 +0000 | [diff] [blame] | 603 | // Mark the decl as visited. |
| 604 | if (VisitedCallees) |
| 605 | VisitedCallees->insert(D); |
| 606 | |
Ted Kremenek | 7fa9b4f | 2012-06-01 20:04:04 +0000 | [diff] [blame] | 607 | return true; |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 608 | } |
| 609 | |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 610 | static ProgramStateRef getInlineFailedState(ProgramStateRef State, |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 611 | const Stmt *CallE) { |
Jordan Rose | bdc691f | 2013-01-14 18:58:42 +0000 | [diff] [blame] | 612 | const void *ReplayState = State->get<ReplayWithoutInlining>(); |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 613 | if (!ReplayState) |
| 614 | return 0; |
Jordan Rose | 28038f3 | 2012-07-10 22:07:42 +0000 | [diff] [blame] | 615 | |
Jordan Rose | bdc691f | 2013-01-14 18:58:42 +0000 | [diff] [blame] | 616 | assert(ReplayState == CallE && "Backtracked to the wrong call."); |
Jordan Rose | 28038f3 | 2012-07-10 22:07:42 +0000 | [diff] [blame] | 617 | (void)CallE; |
| 618 | |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 619 | return State->remove<ReplayWithoutInlining>(); |
Ted Kremenek | 10520d7 | 2012-02-09 21:59:52 +0000 | [diff] [blame] | 620 | } |
| 621 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 622 | void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, |
| 623 | ExplodedNodeSet &dst) { |
| 624 | // Perform the previsit of the CallExpr. |
| 625 | ExplodedNodeSet dstPreVisit; |
| 626 | getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 627 | |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 628 | // Get the call in its initial state. We use this as a template to perform |
| 629 | // all the checks. |
| 630 | CallEventManager &CEMgr = getStateManager().getCallEventManager(); |
Jordan Rose | 645baee | 2012-08-13 23:46:05 +0000 | [diff] [blame] | 631 | CallEventRef<> CallTemplate |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 632 | = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext()); |
Anna Zaks | 5903a37 | 2012-03-27 20:02:53 +0000 | [diff] [blame] | 633 | |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 634 | // Evaluate the function call. We try each of the checkers |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 635 | // to see if the can evaluate the function call. |
| 636 | ExplodedNodeSet dstCallEvaluated; |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 637 | for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); |
| 638 | I != E; ++I) { |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 639 | evalCall(dstCallEvaluated, *I, *CallTemplate); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 640 | } |
| 641 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 642 | // Finally, perform the post-condition check of the CallExpr and store |
| 643 | // the created nodes in 'Dst'. |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 644 | // Note that if the call was inlined, dstCallEvaluated will be empty. |
| 645 | // The post-CallExpr check will occur in processCallExit. |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 646 | getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, |
| 647 | *this); |
| 648 | } |
| 649 | |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 650 | void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, |
Jordan Rose | 645baee | 2012-08-13 23:46:05 +0000 | [diff] [blame] | 651 | const CallEvent &Call) { |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 652 | // WARNING: At this time, the state attached to 'Call' may be older than the |
| 653 | // state in 'Pred'. This is a minor optimization since CheckerManager will |
| 654 | // use an updated CallEvent instance when calling checkers, but if 'Call' is |
| 655 | // ever used directly in this function all callers should be updated to pass |
| 656 | // the most recent state. (It is probably not worth doing the work here since |
| 657 | // for some callers this will not be necessary.) |
| 658 | |
Jordan Rose | 96479da | 2012-07-02 19:28:16 +0000 | [diff] [blame] | 659 | // Run any pre-call checks using the generic call interface. |
| 660 | ExplodedNodeSet dstPreVisit; |
| 661 | getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this); |
| 662 | |
| 663 | // Actually evaluate the function call. We try each of the checkers |
| 664 | // to see if the can evaluate the function call, and get a callback at |
| 665 | // defaultEvalCall if all of them fail. |
| 666 | ExplodedNodeSet dstCallEvaluated; |
| 667 | getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, |
| 668 | Call, *this); |
| 669 | |
| 670 | // Finally, run any post-call checks. |
| 671 | getCheckerManager().runCheckersForPostCall(Dst, dstCallEvaluated, |
| 672 | Call, *this); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 673 | } |
| 674 | |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 675 | ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, |
| 676 | const LocationContext *LCtx, |
| 677 | ProgramStateRef State) { |
| 678 | const Expr *E = Call.getOriginExpr(); |
| 679 | if (!E) |
| 680 | return State; |
| 681 | |
| 682 | // Some method families have known return values. |
| 683 | if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { |
| 684 | switch (Msg->getMethodFamily()) { |
| 685 | default: |
| 686 | break; |
| 687 | case OMF_autorelease: |
| 688 | case OMF_retain: |
| 689 | case OMF_self: { |
| 690 | // These methods return their receivers. |
| 691 | return State->BindExpr(E, LCtx, Msg->getReceiverSVal()); |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 692 | } |
| 693 | } |
Jordan Rose | e460c46 | 2012-07-26 20:04:25 +0000 | [diff] [blame] | 694 | } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){ |
Jordan Rose | 33e83b6 | 2013-01-31 18:04:03 +0000 | [diff] [blame^] | 695 | return State->BindExpr(E, LCtx, C->getCXXThisVal()); |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 696 | } |
| 697 | |
| 698 | // Conjure a symbol if the return value is unknown. |
| 699 | QualType ResultTy = Call.getResultType(); |
| 700 | SValBuilder &SVB = getSValBuilder(); |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 701 | unsigned Count = currBldrCtx->blockCount(); |
Ted Kremenek | 3b1df8b | 2012-08-22 06:26:06 +0000 | [diff] [blame] | 702 | SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count); |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 703 | return State->BindExpr(E, LCtx, R); |
| 704 | } |
| 705 | |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 706 | // Conservatively evaluate call by invalidating regions and binding |
| 707 | // a conjured return value. |
| 708 | void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, |
| 709 | ExplodedNode *Pred, ProgramStateRef State) { |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 710 | State = Call.invalidateRegions(currBldrCtx->blockCount(), State); |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 711 | State = bindReturnValue(Call, Pred->getLocationContext(), State); |
| 712 | |
| 713 | // And make the result node. |
| 714 | Bldr.generateNode(Call.getProgramPoint(), State, Pred); |
| 715 | } |
| 716 | |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 717 | void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 718 | const CallEvent &CallTemplate) { |
| 719 | // Make sure we have the most recent state attached to the call. |
| 720 | ProgramStateRef State = Pred->getState(); |
| 721 | CallEventRef<> Call = CallTemplate.cloneWithState(State); |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 722 | |
Anna Zaks | 75f31c4 | 2012-12-07 21:51:47 +0000 | [diff] [blame] | 723 | if (HowToInline == Inline_None) { |
Anna Zaks | 5960f4a | 2012-08-09 18:43:00 +0000 | [diff] [blame] | 724 | conservativeEvalCall(*Call, Bldr, Pred, State); |
| 725 | return; |
| 726 | } |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 727 | // Try to inline the call. |
Jordan Rose | 28038f3 | 2012-07-10 22:07:42 +0000 | [diff] [blame] | 728 | // The origin expression here is just used as a kind of checksum; |
Jordan Rose | d563d3f | 2012-07-30 20:22:09 +0000 | [diff] [blame] | 729 | // this should still be safe even for CallEvents that don't come from exprs. |
| 730 | const Expr *E = Call->getOriginExpr(); |
| 731 | ProgramStateRef InlinedFailedState = getInlineFailedState(State, E); |
| 732 | |
| 733 | if (InlinedFailedState) { |
| 734 | // If we already tried once and failed, make sure we don't retry later. |
| 735 | State = InlinedFailedState; |
Anna Zaks | 5960f4a | 2012-08-09 18:43:00 +0000 | [diff] [blame] | 736 | } else { |
Ted Kremenek | ddc0c48 | 2012-09-21 06:13:13 +0000 | [diff] [blame] | 737 | RuntimeDefinition RD = Call->getRuntimeDefinition(); |
Anna Zaks | fc05dec | 2012-08-09 02:57:02 +0000 | [diff] [blame] | 738 | const Decl *D = RD.getDecl(); |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 739 | if (D) { |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 740 | if (RD.mayHaveOtherDefinitions()) { |
Anna Zaks | 73f0563 | 2013-01-24 23:15:25 +0000 | [diff] [blame] | 741 | AnalyzerOptions &Options = getAnalysisManager().options; |
| 742 | |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 743 | // Explore with and without inlining the call. |
Anna Zaks | bfa9ab8 | 2013-01-24 23:15:30 +0000 | [diff] [blame] | 744 | if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) { |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 745 | BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); |
| 746 | return; |
| 747 | } |
| 748 | |
| 749 | // Don't inline if we're not in any dynamic dispatch mode. |
Anna Zaks | bfa9ab8 | 2013-01-24 23:15:30 +0000 | [diff] [blame] | 750 | if (Options.getIPAMode() != IPAK_DynamicDispatch) { |
Jordan Rose | da29ac5 | 2012-08-15 21:05:15 +0000 | [diff] [blame] | 751 | conservativeEvalCall(*Call, Bldr, Pred, State); |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 752 | return; |
Jordan Rose | da29ac5 | 2012-08-15 21:05:15 +0000 | [diff] [blame] | 753 | } |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 754 | } |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 755 | |
Anna Zaks | 5960f4a | 2012-08-09 18:43:00 +0000 | [diff] [blame] | 756 | // We are not bifurcating and we do have a Decl, so just inline. |
| 757 | if (inlineCall(*Call, D, Bldr, Pred, State)) |
| 758 | return; |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 759 | } |
Anna Zaks | e81ce25 | 2012-07-19 23:38:13 +0000 | [diff] [blame] | 760 | } |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 761 | |
| 762 | // If we can't inline it, handle the return value and invalidate the regions. |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 763 | conservativeEvalCall(*Call, Bldr, Pred, State); |
Jordan Rose | 69f87c9 | 2012-07-02 19:28:09 +0000 | [diff] [blame] | 764 | } |
| 765 | |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 766 | void ExprEngine::BifurcateCall(const MemRegion *BifurReg, |
| 767 | const CallEvent &Call, const Decl *D, |
| 768 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 769 | assert(BifurReg); |
Jordan Rose | b763ede | 2012-08-15 00:52:00 +0000 | [diff] [blame] | 770 | BifurReg = BifurReg->StripCasts(); |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 771 | |
| 772 | // Check if we've performed the split already - note, we only want |
| 773 | // to split the path once per memory region. |
| 774 | ProgramStateRef State = Pred->getState(); |
Jordan Rose | 166d502 | 2012-11-02 01:54:06 +0000 | [diff] [blame] | 775 | const unsigned *BState = |
Anna Zaks | 6960f6e | 2012-08-09 21:02:41 +0000 | [diff] [blame] | 776 | State->get<DynamicDispatchBifurcationMap>(BifurReg); |
Anna Zaks | 5960f4a | 2012-08-09 18:43:00 +0000 | [diff] [blame] | 777 | if (BState) { |
| 778 | // If we are on "inline path", keep inlining if possible. |
Anna Zaks | 6960f6e | 2012-08-09 21:02:41 +0000 | [diff] [blame] | 779 | if (*BState == DynamicDispatchModeInlined) |
Anna Zaks | 5960f4a | 2012-08-09 18:43:00 +0000 | [diff] [blame] | 780 | if (inlineCall(Call, D, Bldr, Pred, State)) |
| 781 | return; |
| 782 | // If inline failed, or we are on the path where we assume we |
| 783 | // don't have enough info about the receiver to inline, conjure the |
| 784 | // return value and invalidate the regions. |
| 785 | conservativeEvalCall(Call, Bldr, Pred, State); |
| 786 | return; |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 787 | } |
| 788 | |
| 789 | // If we got here, this is the first time we process a message to this |
| 790 | // region, so split the path. |
| 791 | ProgramStateRef IState = |
Anna Zaks | 6960f6e | 2012-08-09 21:02:41 +0000 | [diff] [blame] | 792 | State->set<DynamicDispatchBifurcationMap>(BifurReg, |
| 793 | DynamicDispatchModeInlined); |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 794 | inlineCall(Call, D, Bldr, Pred, IState); |
| 795 | |
| 796 | ProgramStateRef NoIState = |
Anna Zaks | 6960f6e | 2012-08-09 21:02:41 +0000 | [diff] [blame] | 797 | State->set<DynamicDispatchBifurcationMap>(BifurReg, |
| 798 | DynamicDispatchModeConservative); |
Anna Zaks | e90d3f8 | 2012-08-09 00:21:33 +0000 | [diff] [blame] | 799 | conservativeEvalCall(Call, Bldr, Pred, NoIState); |
| 800 | |
| 801 | NumOfDynamicDispatchPathSplits++; |
| 802 | return; |
| 803 | } |
| 804 | |
| 805 | |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 806 | void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, |
| 807 | ExplodedNodeSet &Dst) { |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 808 | |
| 809 | ExplodedNodeSet dstPreVisit; |
| 810 | getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); |
| 811 | |
Ted Kremenek | 66c486f | 2012-08-22 06:26:15 +0000 | [diff] [blame] | 812 | StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); |
Ted Kremenek | 256ef64 | 2012-01-11 01:06:27 +0000 | [diff] [blame] | 813 | |
| 814 | if (RS->getRetValue()) { |
| 815 | for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), |
| 816 | ei = dstPreVisit.end(); it != ei; ++it) { |
| 817 | B.generateNode(RS, *it, (*it)->getState()); |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 818 | } |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 819 | } |
Ted Kremenek | 294fd0a | 2011-08-20 06:00:03 +0000 | [diff] [blame] | 820 | } |