1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
16 | #include "PrettyStackTraceLocationContext.h" |
17 | #include "clang/AST/ASTContext.h" |
18 | #include "clang/AST/Decl.h" |
19 | #include "clang/AST/DeclBase.h" |
20 | #include "clang/AST/DeclCXX.h" |
21 | #include "clang/AST/DeclObjC.h" |
22 | #include "clang/AST/Expr.h" |
23 | #include "clang/AST/ExprCXX.h" |
24 | #include "clang/AST/ExprObjC.h" |
25 | #include "clang/AST/ParentMap.h" |
26 | #include "clang/AST/PrettyPrinter.h" |
27 | #include "clang/AST/Stmt.h" |
28 | #include "clang/AST/StmtCXX.h" |
29 | #include "clang/AST/StmtObjC.h" |
30 | #include "clang/AST/Type.h" |
31 | #include "clang/Analysis/AnalysisDeclContext.h" |
32 | #include "clang/Analysis/CFG.h" |
33 | #include "clang/Analysis/ConstructionContext.h" |
34 | #include "clang/Analysis/ProgramPoint.h" |
35 | #include "clang/Basic/IdentifierTable.h" |
36 | #include "clang/Basic/LLVM.h" |
37 | #include "clang/Basic/LangOptions.h" |
38 | #include "clang/Basic/PrettyStackTrace.h" |
39 | #include "clang/Basic/SourceLocation.h" |
40 | #include "clang/Basic/SourceManager.h" |
41 | #include "clang/Basic/Specifiers.h" |
42 | #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" |
43 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" |
44 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
45 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
46 | #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" |
47 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
48 | #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" |
49 | #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" |
50 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" |
51 | #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h" |
52 | #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" |
53 | #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" |
54 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
55 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" |
56 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
57 | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
58 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
59 | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
60 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
61 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
62 | #include "llvm/ADT/APSInt.h" |
63 | #include "llvm/ADT/DenseMap.h" |
64 | #include "llvm/ADT/ImmutableMap.h" |
65 | #include "llvm/ADT/ImmutableSet.h" |
66 | #include "llvm/ADT/Optional.h" |
67 | #include "llvm/ADT/SmallVector.h" |
68 | #include "llvm/ADT/Statistic.h" |
69 | #include "llvm/Support/Casting.h" |
70 | #include "llvm/Support/Compiler.h" |
71 | #include "llvm/Support/DOTGraphTraits.h" |
72 | #include "llvm/Support/ErrorHandling.h" |
73 | #include "llvm/Support/GraphWriter.h" |
74 | #include "llvm/Support/SaveAndRestore.h" |
75 | #include "llvm/Support/raw_ostream.h" |
76 | #include <cassert> |
77 | #include <cstdint> |
78 | #include <memory> |
79 | #include <string> |
80 | #include <tuple> |
81 | #include <utility> |
82 | #include <vector> |
83 | |
84 | using namespace clang; |
85 | using namespace ento; |
86 | |
87 | #define DEBUG_TYPE "ExprEngine" |
88 | |
89 | STATISTIC(NumRemoveDeadBindings, |
90 | "The # of times RemoveDeadBindings is called"); |
91 | STATISTIC(NumMaxBlockCountReached, |
92 | "The # of aborted paths due to reaching the maximum block count in " |
93 | "a top level function"); |
94 | STATISTIC(NumMaxBlockCountReachedInInlined, |
95 | "The # of aborted paths due to reaching the maximum block count in " |
96 | "an inlined function"); |
97 | STATISTIC(NumTimesRetriedWithoutInlining, |
98 | "The # of times we re-evaluated a call without inlining"); |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | namespace { |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | class ConstructedObjectKey { |
120 | typedef std::pair<ConstructionContextItem, const LocationContext *> |
121 | ConstructedObjectKeyImpl; |
122 | |
123 | const ConstructedObjectKeyImpl Impl; |
124 | |
125 | const void *getAnyASTNodePtr() const { |
126 | if (const Stmt *S = getItem().getStmtOrNull()) |
127 | return S; |
128 | else |
129 | return getItem().getCXXCtorInitializer(); |
130 | } |
131 | |
132 | public: |
133 | explicit ConstructedObjectKey(const ConstructionContextItem &Item, |
134 | const LocationContext *LC) |
135 | : Impl(Item, LC) {} |
136 | |
137 | const ConstructionContextItem &getItem() const { return Impl.first; } |
138 | const LocationContext *getLocationContext() const { return Impl.second; } |
139 | |
140 | ASTContext &getASTContext() const { |
141 | return getLocationContext()->getDecl()->getASTContext(); |
142 | } |
143 | |
144 | void print(llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) { |
145 | OS << "(LC" << getLocationContext()->getID() << ','; |
146 | if (const Stmt *S = getItem().getStmtOrNull()) |
147 | OS << 'S' << S->getID(getASTContext()); |
148 | else |
149 | OS << 'I' << getItem().getCXXCtorInitializer()->getID(getASTContext()); |
150 | OS << ',' << getItem().getKindAsString(); |
151 | if (getItem().getKind() == ConstructionContextItem::ArgumentKind) |
152 | OS << " #" << getItem().getIndex(); |
153 | OS << ") "; |
154 | if (const Stmt *S = getItem().getStmtOrNull()) { |
155 | S->printPretty(OS, Helper, PP); |
156 | } else { |
157 | const CXXCtorInitializer *I = getItem().getCXXCtorInitializer(); |
158 | OS << I->getAnyMember()->getNameAsString(); |
159 | } |
160 | } |
161 | |
162 | void Profile(llvm::FoldingSetNodeID &ID) const { |
163 | ID.Add(Impl.first); |
164 | ID.AddPointer(Impl.second); |
165 | } |
166 | |
167 | bool operator==(const ConstructedObjectKey &RHS) const { |
168 | return Impl == RHS.Impl; |
169 | } |
170 | |
171 | bool operator<(const ConstructedObjectKey &RHS) const { |
172 | return Impl < RHS.Impl; |
173 | } |
174 | }; |
175 | } |
176 | |
177 | typedef llvm::ImmutableMap<ConstructedObjectKey, SVal> |
178 | ObjectsUnderConstructionMap; |
179 | REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, |
180 | ObjectsUnderConstructionMap) |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | static const char* TagProviderName = "ExprEngine"; |
187 | |
188 | ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, |
189 | AnalysisManager &mgr, |
190 | SetOfConstDecls *VisitedCalleesIn, |
191 | FunctionSummariesTy *FS, |
192 | InliningModes HowToInlineIn) |
193 | : CTU(CTU), AMgr(mgr), |
194 | AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()), |
195 | Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()), |
196 | StateMgr(getContext(), mgr.getStoreManagerCreator(), |
197 | mgr.getConstraintManagerCreator(), G.getAllocator(), |
198 | this), |
199 | SymMgr(StateMgr.getSymbolManager()), |
200 | MRMgr(StateMgr.getRegionManager()), |
201 | svalBuilder(StateMgr.getSValBuilder()), |
202 | ObjCNoRet(mgr.getASTContext()), |
203 | BR(mgr, *this), |
204 | VisitedCallees(VisitedCalleesIn), HowToInline(HowToInlineIn) { |
205 | unsigned TrimInterval = mgr.options.GraphTrimInterval; |
206 | if (TrimInterval != 0) { |
207 | |
208 | G.enableNodeReclamation(TrimInterval); |
209 | } |
210 | } |
211 | |
212 | ExprEngine::~ExprEngine() { |
213 | BR.FlushReports(); |
214 | } |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { |
221 | ProgramStateRef state = StateMgr.getInitialState(InitLoc); |
222 | const Decl *D = InitLoc->getDecl(); |
223 | |
224 | |
225 | |
226 | |
227 | do { |
228 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
229 | |
230 | |
231 | const IdentifierInfo *II = FD->getIdentifier(); |
232 | if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) |
233 | break; |
234 | |
235 | const ParmVarDecl *PD = FD->getParamDecl(0); |
236 | QualType T = PD->getType(); |
237 | const auto *BT = dyn_cast<BuiltinType>(T); |
238 | if (!BT || !BT->isInteger()) |
239 | break; |
240 | |
241 | const MemRegion *R = state->getRegion(PD, InitLoc); |
242 | if (!R) |
243 | break; |
244 | |
245 | SVal V = state->getSVal(loc::MemRegionVal(R)); |
246 | SVal Constraint_untested = evalBinOp(state, BO_GT, V, |
247 | svalBuilder.makeZeroVal(T), |
248 | svalBuilder.getConditionType()); |
249 | |
250 | Optional<DefinedOrUnknownSVal> Constraint = |
251 | Constraint_untested.getAs<DefinedOrUnknownSVal>(); |
252 | |
253 | if (!Constraint) |
254 | break; |
255 | |
256 | if (ProgramStateRef newState = state->assume(*Constraint, true)) |
257 | state = newState; |
258 | } |
259 | break; |
260 | } |
261 | while (false); |
262 | |
263 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { |
264 | |
265 | |
266 | const ImplicitParamDecl *SelfD = MD->getSelfDecl(); |
267 | const MemRegion *R = state->getRegion(SelfD, InitLoc); |
268 | SVal V = state->getSVal(loc::MemRegionVal(R)); |
269 | |
270 | if (Optional<Loc> LV = V.getAs<Loc>()) { |
271 | |
272 | state = state->assume(*LV, true); |
273 | (0) . __assert_fail ("state && \"'self' cannot be null\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 273, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(state && "'self' cannot be null"); |
274 | } |
275 | } |
276 | |
277 | if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
278 | if (!MD->isStatic()) { |
279 | |
280 | |
281 | |
282 | const StackFrameContext *SFC = InitLoc->getStackFrame(); |
283 | if (SFC->getParent() == nullptr) { |
284 | loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC); |
285 | SVal V = state->getSVal(L); |
286 | if (Optional<Loc> LV = V.getAs<Loc>()) { |
287 | state = state->assume(*LV, true); |
288 | (0) . __assert_fail ("state && \"'this' cannot be null\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 288, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(state && "'this' cannot be null"); |
289 | } |
290 | } |
291 | } |
292 | } |
293 | |
294 | return state; |
295 | } |
296 | |
297 | ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( |
298 | ProgramStateRef State, const LocationContext *LC, |
299 | const Expr *InitWithAdjustments, const Expr *Result, |
300 | const SubRegion **OutRegionWithAdjustments) { |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | SVal InitValWithAdjustments = State->getSVal(InitWithAdjustments, LC); |
307 | if (!Result) { |
308 | |
309 | |
310 | if (!InitValWithAdjustments.getAs<NonLoc>()) { |
311 | if (OutRegionWithAdjustments) |
312 | *OutRegionWithAdjustments = nullptr; |
313 | return State; |
314 | } |
315 | Result = InitWithAdjustments; |
316 | } else { |
317 | |
318 | |
319 | () || Loc..isLocType(Result->getType()) || Result->getType()->isMemberPointerType()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 321, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!InitValWithAdjustments.getAs<Loc>() || |
320 | () || Loc..isLocType(Result->getType()) || Result->getType()->isMemberPointerType()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 321, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Loc::isLocType(Result->getType()) || |
321 | () || Loc..isLocType(Result->getType()) || Result->getType()->isMemberPointerType()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 321, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Result->getType()->isMemberPointerType()); |
322 | } |
323 | |
324 | ProgramStateManager &StateMgr = State->getStateManager(); |
325 | MemRegionManager &MRMgr = StateMgr.getRegionManager(); |
326 | StoreManager &StoreMgr = StateMgr.getStoreManager(); |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | |
348 | |
349 | SmallVector<const Expr *, 2> CommaLHSs; |
350 | SmallVector<SubobjectAdjustment, 2> Adjustments; |
351 | |
352 | const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments( |
353 | CommaLHSs, Adjustments); |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | |
360 | const TypedValueRegion *TR = nullptr; |
361 | if (const auto *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) { |
362 | if (Optional<SVal> V = getObjectUnderConstruction(State, MT, LC)) { |
363 | State = finishObjectConstruction(State, MT, LC); |
364 | State = State->BindExpr(Result, LC, *V); |
365 | return State; |
366 | } else { |
367 | StorageDuration SD = MT->getStorageDuration(); |
368 | |
369 | |
370 | if (SD == SD_Static || SD == SD_Thread) { |
371 | TR = MRMgr.getCXXStaticTempObjectRegion(Init); |
372 | } else { |
373 | TR = MRMgr.getCXXTempObjectRegion(Init, LC); |
374 | } |
375 | } |
376 | } else { |
377 | TR = MRMgr.getCXXTempObjectRegion(Init, LC); |
378 | } |
379 | |
380 | SVal Reg = loc::MemRegionVal(TR); |
381 | SVal BaseReg = Reg; |
382 | |
383 | |
384 | for (auto I = Adjustments.rbegin(), E = Adjustments.rend(); I != E; ++I) { |
385 | const SubobjectAdjustment &Adj = *I; |
386 | switch (Adj.Kind) { |
387 | case SubobjectAdjustment::DerivedToBaseAdjustment: |
388 | Reg = StoreMgr.evalDerivedToBase(Reg, Adj.DerivedToBase.BasePath); |
389 | break; |
390 | case SubobjectAdjustment::FieldAdjustment: |
391 | Reg = StoreMgr.getLValueField(Adj.Field, Reg); |
392 | break; |
393 | case SubobjectAdjustment::MemberPointerAdjustment: |
394 | |
395 | State = State->invalidateRegions(Reg, InitWithAdjustments, |
396 | currBldrCtx->blockCount(), LC, true, |
397 | nullptr, nullptr, nullptr); |
398 | return State; |
399 | } |
400 | } |
401 | |
402 | |
403 | |
404 | |
405 | |
406 | |
407 | |
408 | |
409 | |
410 | SVal InitVal = State->getSVal(Init, LC); |
411 | if (InitVal.isUnknown()) { |
412 | InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(), |
413 | currBldrCtx->blockCount()); |
414 | State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false); |
415 | |
416 | |
417 | |
418 | if (InitValWithAdjustments.isUnknown()) { |
419 | |
420 | |
421 | InitValWithAdjustments = getSValBuilder().conjureSymbolVal( |
422 | Result, LC, InitWithAdjustments->getType(), |
423 | currBldrCtx->blockCount()); |
424 | } |
425 | State = |
426 | State->bindLoc(Reg.castAs<Loc>(), InitValWithAdjustments, LC, false); |
427 | } else { |
428 | State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false); |
429 | } |
430 | |
431 | |
432 | |
433 | |
434 | if (Result->isGLValue()) { |
435 | State = State->BindExpr(Result, LC, Reg); |
436 | } else { |
437 | State = State->BindExpr(Result, LC, InitValWithAdjustments); |
438 | } |
439 | |
440 | |
441 | State = processRegionChange(State, TR, LC); |
442 | |
443 | if (OutRegionWithAdjustments) |
444 | *OutRegionWithAdjustments = cast<SubRegion>(Reg.getAsRegion()); |
445 | return State; |
446 | } |
447 | |
448 | ProgramStateRef |
449 | ExprEngine::addObjectUnderConstruction(ProgramStateRef State, |
450 | const ConstructionContextItem &Item, |
451 | const LocationContext *LC, SVal V) { |
452 | ConstructedObjectKey Key(Item, LC->getStackFrame()); |
453 | |
454 | |
455 | get(Key) || Key.getItem().getKind() == ConstructionContextItem..TemporaryDestructorKind", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 457, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!State->get<ObjectsUnderConstruction>(Key) || |
456 | get(Key) || Key.getItem().getKind() == ConstructionContextItem..TemporaryDestructorKind", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 457, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Key.getItem().getKind() == |
457 | get(Key) || Key.getItem().getKind() == ConstructionContextItem..TemporaryDestructorKind", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 457, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> ConstructionContextItem::TemporaryDestructorKind); |
458 | return State->set<ObjectsUnderConstruction>(Key, V); |
459 | } |
460 | |
461 | Optional<SVal> |
462 | ExprEngine::getObjectUnderConstruction(ProgramStateRef State, |
463 | const ConstructionContextItem &Item, |
464 | const LocationContext *LC) { |
465 | ConstructedObjectKey Key(Item, LC->getStackFrame()); |
466 | return Optional<SVal>::create(State->get<ObjectsUnderConstruction>(Key)); |
467 | } |
468 | |
469 | ProgramStateRef |
470 | ExprEngine::finishObjectConstruction(ProgramStateRef State, |
471 | const ConstructionContextItem &Item, |
472 | const LocationContext *LC) { |
473 | ConstructedObjectKey Key(Item, LC->getStackFrame()); |
474 | contains(Key)", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 474, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(State->contains<ObjectsUnderConstruction>(Key)); |
475 | return State->remove<ObjectsUnderConstruction>(Key); |
476 | } |
477 | |
478 | ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State, |
479 | const CXXBindTemporaryExpr *BTE, |
480 | const LocationContext *LC) { |
481 | ConstructedObjectKey Key({BTE, }, LC); |
482 | |
483 | |
484 | return State->set<ObjectsUnderConstruction>(Key, UnknownVal()); |
485 | } |
486 | |
487 | ProgramStateRef |
488 | ExprEngine::cleanupElidedDestructor(ProgramStateRef State, |
489 | const CXXBindTemporaryExpr *BTE, |
490 | const LocationContext *LC) { |
491 | ConstructedObjectKey Key({BTE, }, LC); |
492 | contains(Key)", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 492, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(State->contains<ObjectsUnderConstruction>(Key)); |
493 | return State->remove<ObjectsUnderConstruction>(Key); |
494 | } |
495 | |
496 | bool ExprEngine::isDestructorElided(ProgramStateRef State, |
497 | const CXXBindTemporaryExpr *BTE, |
498 | const LocationContext *LC) { |
499 | ConstructedObjectKey Key({BTE, }, LC); |
500 | return State->contains<ObjectsUnderConstruction>(Key); |
501 | } |
502 | |
503 | bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State, |
504 | const LocationContext *FromLC, |
505 | const LocationContext *ToLC) { |
506 | const LocationContext *LC = FromLC; |
507 | while (LC != ToLC) { |
508 | (0) . __assert_fail ("LC && \"ToLC must be a parent of FromLC!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 508, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(LC && "ToLC must be a parent of FromLC!"); |
509 | for (auto I : State->get<ObjectsUnderConstruction>()) |
510 | if (I.first.getLocationContext() == LC) |
511 | return false; |
512 | |
513 | LC = LC->getParent(); |
514 | } |
515 | return true; |
516 | } |
517 | |
518 | |
519 | |
520 | |
521 | |
522 | |
523 | |
524 | |
525 | ProgramStateRef ExprEngine::processAssume(ProgramStateRef state, |
526 | SVal cond, bool assumption) { |
527 | return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); |
528 | } |
529 | |
530 | ProgramStateRef |
531 | ExprEngine::processRegionChanges(ProgramStateRef state, |
532 | const InvalidatedSymbols *invalidated, |
533 | ArrayRef<const MemRegion *> Explicits, |
534 | ArrayRef<const MemRegion *> Regions, |
535 | const LocationContext *LCtx, |
536 | const CallEvent *Call) { |
537 | return getCheckerManager().runCheckersForRegionChanges(state, invalidated, |
538 | Explicits, Regions, |
539 | LCtx, Call); |
540 | } |
541 | |
542 | static void printObjectsUnderConstructionForContext(raw_ostream &Out, |
543 | ProgramStateRef State, |
544 | const char *NL, |
545 | const LocationContext *LC) { |
546 | PrintingPolicy PP = |
547 | LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); |
548 | for (auto I : State->get<ObjectsUnderConstruction>()) { |
549 | ConstructedObjectKey Key = I.first; |
550 | SVal Value = I.second; |
551 | if (Key.getLocationContext() != LC) |
552 | continue; |
553 | Key.print(Out, nullptr, PP); |
554 | Out << " : " << Value << NL; |
555 | } |
556 | } |
557 | |
558 | void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State, |
559 | const char *NL, const char *Sep, |
560 | const LocationContext *LCtx) { |
561 | if (LCtx) { |
562 | if (!State->get<ObjectsUnderConstruction>().isEmpty()) { |
563 | Out << Sep << "Objects under construction:" << NL; |
564 | |
565 | LCtx->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) { |
566 | printObjectsUnderConstructionForContext(Out, State, NL, LC); |
567 | }); |
568 | } |
569 | } |
570 | |
571 | getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep); |
572 | } |
573 | |
574 | void ExprEngine::processEndWorklist() { |
575 | getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); |
576 | } |
577 | |
578 | void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, |
579 | unsigned StmtIdx, NodeBuilderContext *Ctx) { |
580 | PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); |
581 | currStmtIdx = StmtIdx; |
582 | currBldrCtx = Ctx; |
583 | |
584 | switch (E.getKind()) { |
585 | case CFGElement::Statement: |
586 | case CFGElement::Constructor: |
587 | case CFGElement::CXXRecordTypedCall: |
588 | ProcessStmt(E.castAs<CFGStmt>().getStmt(), Pred); |
589 | return; |
590 | case CFGElement::Initializer: |
591 | ProcessInitializer(E.castAs<CFGInitializer>(), Pred); |
592 | return; |
593 | case CFGElement::NewAllocator: |
594 | ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(), |
595 | Pred); |
596 | return; |
597 | case CFGElement::AutomaticObjectDtor: |
598 | case CFGElement::DeleteDtor: |
599 | case CFGElement::BaseDtor: |
600 | case CFGElement::MemberDtor: |
601 | case CFGElement::TemporaryDtor: |
602 | ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred); |
603 | return; |
604 | case CFGElement::LoopExit: |
605 | ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred); |
606 | return; |
607 | case CFGElement::LifetimeEnds: |
608 | case CFGElement::ScopeBegin: |
609 | case CFGElement::ScopeEnd: |
610 | return; |
611 | } |
612 | } |
613 | |
614 | static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, |
615 | const Stmt *S, |
616 | const ExplodedNode *Pred, |
617 | const LocationContext *LC) { |
618 | |
619 | if (AMgr.options.AnalysisPurgeOpt == PurgeNone) |
620 | return false; |
621 | |
622 | |
623 | if (Pred->getLocation().getAs<BlockEntrance>()) |
624 | return true; |
625 | |
626 | |
627 | if (!isa<Expr>(S)) |
628 | return true; |
629 | |
630 | |
631 | if (CallEvent::isCallStmt(S)) |
632 | return true; |
633 | |
634 | |
635 | |
636 | ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap(); |
637 | return !PM.isConsumedExpr(cast<Expr>(S)); |
638 | } |
639 | |
640 | void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, |
641 | const Stmt *ReferenceStmt, |
642 | const LocationContext *LC, |
643 | const Stmt *DiagnosticStmt, |
644 | ProgramPoint::Kind K) { |
645 | (0) . __assert_fail ("(K == ProgramPoint..PreStmtPurgeDeadSymbolsKind || ReferenceStmt == nullptr || isa(ReferenceStmt)) && \"PostStmt is not generally supported by the SymbolReaper yet\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 647, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || |
646 | (0) . __assert_fail ("(K == ProgramPoint..PreStmtPurgeDeadSymbolsKind || ReferenceStmt == nullptr || isa(ReferenceStmt)) && \"PostStmt is not generally supported by the SymbolReaper yet\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 647, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt)) |
647 | (0) . __assert_fail ("(K == ProgramPoint..PreStmtPurgeDeadSymbolsKind || ReferenceStmt == nullptr || isa(ReferenceStmt)) && \"PostStmt is not generally supported by the SymbolReaper yet\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 647, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> && "PostStmt is not generally supported by the SymbolReaper yet"); |
648 | (0) . __assert_fail ("LC && \"Must pass the current (or expiring) LocationContext\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 648, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(LC && "Must pass the current (or expiring) LocationContext"); |
649 | |
650 | if (!DiagnosticStmt) { |
651 | DiagnosticStmt = ReferenceStmt; |
652 | (0) . __assert_fail ("DiagnosticStmt && \"Required for clearing a LocationContext\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 652, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagnosticStmt && "Required for clearing a LocationContext"); |
653 | } |
654 | |
655 | NumRemoveDeadBindings++; |
656 | ProgramStateRef CleanedState = Pred->getState(); |
657 | |
658 | |
659 | |
660 | |
661 | if (!ReferenceStmt) { |
662 | (0) . __assert_fail ("K == ProgramPoint..PostStmtPurgeDeadSymbolsKind && \"Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 663, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind && |
663 | (0) . __assert_fail ("K == ProgramPoint..PostStmtPurgeDeadSymbolsKind && \"Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 663, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext"); |
664 | LC = LC->getParent(); |
665 | } |
666 | |
667 | const StackFrameContext *SFC = LC ? LC->getStackFrame() : nullptr; |
668 | SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager()); |
669 | |
670 | for (auto I : CleanedState->get<ObjectsUnderConstruction>()) { |
671 | if (SymbolRef Sym = I.second.getAsSymbol()) |
672 | SymReaper.markLive(Sym); |
673 | if (const MemRegion *MR = I.second.getAsRegion()) |
674 | SymReaper.markLive(MR); |
675 | } |
676 | |
677 | getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); |
678 | |
679 | |
680 | |
681 | |
682 | CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper); |
683 | |
684 | |
685 | |
686 | static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node"); |
687 | |
688 | |
689 | ExplodedNodeSet CheckedSet; |
690 | getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper, |
691 | DiagnosticStmt, *this, K); |
692 | |
693 | |
694 | |
695 | |
696 | StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx); |
697 | for (const auto I : CheckedSet) { |
698 | ProgramStateRef CheckerState = I->getState(); |
699 | |
700 | |
701 | CheckerState = |
702 | getConstraintManager().removeDeadBindings(CheckerState, SymReaper); |
703 | |
704 | (0) . __assert_fail ("StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Environment as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 706, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && |
705 | (0) . __assert_fail ("StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Environment as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 706, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Checkers are not allowed to modify the Environment as a part of " |
706 | (0) . __assert_fail ("StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Environment as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 706, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "checkDeadSymbols processing."); |
707 | (0) . __assert_fail ("StateMgr.haveEqualStores(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Store as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 709, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) && |
708 | (0) . __assert_fail ("StateMgr.haveEqualStores(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Store as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 709, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Checkers are not allowed to modify the Store as a part of " |
709 | (0) . __assert_fail ("StateMgr.haveEqualStores(CheckerState, Pred->getState()) && \"Checkers are not allowed to modify the Store as a part of \" \"checkDeadSymbols processing.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 709, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "checkDeadSymbols processing."); |
710 | |
711 | |
712 | |
713 | ProgramStateRef CleanedCheckerSt = |
714 | StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); |
715 | Bldr.generateNode(DiagnosticStmt, I, CleanedCheckerSt, &cleanupTag, K); |
716 | } |
717 | } |
718 | |
719 | void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) { |
720 | |
721 | G.reclaimRecentlyAllocatedNodes(); |
722 | |
723 | PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), |
724 | currStmt->getBeginLoc(), |
725 | "Error evaluating statement"); |
726 | |
727 | |
728 | ExplodedNodeSet CleanedStates; |
729 | if (shouldRemoveDeadBindings(AMgr, currStmt, Pred, |
730 | Pred->getLocationContext())) { |
731 | removeDead(Pred, CleanedStates, currStmt, |
732 | Pred->getLocationContext()); |
733 | } else |
734 | CleanedStates.Add(Pred); |
735 | |
736 | |
737 | ExplodedNodeSet Dst; |
738 | for (const auto I : CleanedStates) { |
739 | ExplodedNodeSet DstI; |
740 | |
741 | Visit(currStmt, I, DstI); |
742 | Dst.insert(DstI); |
743 | } |
744 | |
745 | |
746 | Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); |
747 | } |
748 | |
749 | void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) { |
750 | PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), |
751 | S->getBeginLoc(), |
752 | "Error evaluating end of the loop"); |
753 | ExplodedNodeSet Dst; |
754 | Dst.Add(Pred); |
755 | NodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
756 | ProgramStateRef NewState = Pred->getState(); |
757 | |
758 | if(AMgr.options.ShouldUnrollLoops) |
759 | NewState = processLoopEnd(S, NewState); |
760 | |
761 | LoopExit PP(S, Pred->getLocationContext()); |
762 | Bldr.generateNode(PP, NewState, Pred); |
763 | |
764 | Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); |
765 | } |
766 | |
767 | void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit, |
768 | ExplodedNode *Pred) { |
769 | const CXXCtorInitializer *BMI = CFGInit.getInitializer(); |
770 | const Expr *Init = BMI->getInit()->IgnoreImplicit(); |
771 | const LocationContext *LC = Pred->getLocationContext(); |
772 | |
773 | PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), |
774 | BMI->getSourceLocation(), |
775 | "Error evaluating initializer"); |
776 | |
777 | |
778 | const auto *stackFrame = cast<StackFrameContext>(Pred->getLocationContext()); |
779 | const auto *decl = cast<CXXConstructorDecl>(stackFrame->getDecl()); |
780 | |
781 | ProgramStateRef State = Pred->getState(); |
782 | SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); |
783 | |
784 | ExplodedNodeSet Tmp; |
785 | SVal FieldLoc; |
786 | |
787 | |
788 | if (BMI->isAnyMemberInitializer()) { |
789 | |
790 | |
791 | if (getObjectUnderConstruction(State, BMI, LC)) { |
792 | |
793 | |
794 | State = finishObjectConstruction(State, BMI, LC); |
795 | NodeBuilder Bldr(Pred, Tmp, *currBldrCtx); |
796 | PostStore PS(Init, LC, nullptr, nullptr); |
797 | Bldr.generateNode(PS, State, Pred); |
798 | } else { |
799 | const ValueDecl *Field; |
800 | if (BMI->isIndirectMemberInitializer()) { |
801 | Field = BMI->getIndirectMember(); |
802 | FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); |
803 | } else { |
804 | Field = BMI->getMember(); |
805 | FieldLoc = State->getLValue(BMI->getMember(), thisVal); |
806 | } |
807 | |
808 | SVal InitVal; |
809 | if (Init->getType()->isArrayType()) { |
810 | |
811 | |
812 | const ArraySubscriptExpr *ASE; |
813 | while ((ASE = dyn_cast<ArraySubscriptExpr>(Init))) |
814 | Init = ASE->getBase()->IgnoreImplicit(); |
815 | |
816 | SVal LValue = State->getSVal(Init, stackFrame); |
817 | if (!Field->getType()->isReferenceType()) |
818 | if (Optional<Loc> LValueLoc = LValue.getAs<Loc>()) |
819 | InitVal = State->getSVal(*LValueLoc); |
820 | |
821 | |
822 | if (InitVal.isUnknownOrUndef()) { |
823 | SValBuilder &SVB = getSValBuilder(); |
824 | InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, |
825 | Field->getType(), |
826 | currBldrCtx->blockCount()); |
827 | } |
828 | } else { |
829 | InitVal = State->getSVal(BMI->getInit(), stackFrame); |
830 | } |
831 | |
832 | PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); |
833 | evalBind(Tmp, Init, Pred, FieldLoc, InitVal, , &PP); |
834 | } |
835 | } else { |
836 | isBaseInitializer() || BMI->isDelegatingInitializer()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 836, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer()); |
837 | Tmp.insert(Pred); |
838 | |
839 | } |
840 | |
841 | |
842 | |
843 | PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); |
844 | ExplodedNodeSet Dst; |
845 | NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); |
846 | for (const auto I : Tmp) { |
847 | ProgramStateRef State = I->getState(); |
848 | Bldr.generateNode(PP, State, I); |
849 | } |
850 | |
851 | |
852 | Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); |
853 | } |
854 | |
855 | void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, |
856 | ExplodedNode *Pred) { |
857 | ExplodedNodeSet Dst; |
858 | switch (D.getKind()) { |
859 | case CFGElement::AutomaticObjectDtor: |
860 | ProcessAutomaticObjDtor(D.castAs<CFGAutomaticObjDtor>(), Pred, Dst); |
861 | break; |
862 | case CFGElement::BaseDtor: |
863 | ProcessBaseDtor(D.castAs<CFGBaseDtor>(), Pred, Dst); |
864 | break; |
865 | case CFGElement::MemberDtor: |
866 | ProcessMemberDtor(D.castAs<CFGMemberDtor>(), Pred, Dst); |
867 | break; |
868 | case CFGElement::TemporaryDtor: |
869 | ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst); |
870 | break; |
871 | case CFGElement::DeleteDtor: |
872 | ProcessDeleteDtor(D.castAs<CFGDeleteDtor>(), Pred, Dst); |
873 | break; |
874 | default: |
875 | llvm_unreachable("Unexpected dtor kind."); |
876 | } |
877 | |
878 | |
879 | Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); |
880 | } |
881 | |
882 | void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, |
883 | ExplodedNode *Pred) { |
884 | ExplodedNodeSet Dst; |
885 | AnalysisManager &AMgr = getAnalysisManager(); |
886 | AnalyzerOptions &Opts = AMgr.options; |
887 | |
888 | |
889 | |
890 | if (Opts.MayInlineCXXAllocator) |
891 | VisitCXXNewAllocatorCall(NE, Pred, Dst); |
892 | else { |
893 | NodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
894 | const LocationContext *LCtx = Pred->getLocationContext(); |
895 | PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx); |
896 | Bldr.generateNode(PP, Pred->getState(), Pred); |
897 | } |
898 | Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); |
899 | } |
900 | |
901 | void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, |
902 | ExplodedNode *Pred, |
903 | ExplodedNodeSet &Dst) { |
904 | const VarDecl *varDecl = Dtor.getVarDecl(); |
905 | QualType varType = varDecl->getType(); |
906 | |
907 | ProgramStateRef state = Pred->getState(); |
908 | SVal dest = state->getLValue(varDecl, Pred->getLocationContext()); |
909 | const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion(); |
910 | |
911 | if (varType->isReferenceType()) { |
912 | const MemRegion *ValueRegion = state->getSVal(Region).getAsRegion(); |
913 | if (!ValueRegion) { |
914 | |
915 | |
916 | |
917 | |
918 | return; |
919 | } |
920 | Region = ValueRegion->getBaseRegion(); |
921 | varType = cast<TypedValueRegion>(Region)->getValueType(); |
922 | } |
923 | |
924 | |
925 | |
926 | |
927 | EvalCallOptions CallOpts; |
928 | Region = makeZeroElementRegion(state, loc::MemRegionVal(Region), varType, |
929 | CallOpts.IsArrayCtorOrDtor).getAsRegion(); |
930 | |
931 | VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), false, |
932 | Pred, Dst, CallOpts); |
933 | } |
934 | |
935 | void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, |
936 | ExplodedNode *Pred, |
937 | ExplodedNodeSet &Dst) { |
938 | ProgramStateRef State = Pred->getState(); |
939 | const LocationContext *LCtx = Pred->getLocationContext(); |
940 | const CXXDeleteExpr *DE = Dtor.getDeleteExpr(); |
941 | const Stmt *Arg = DE->getArgument(); |
942 | QualType DTy = DE->getDestroyedType(); |
943 | SVal ArgVal = State->getSVal(Arg, LCtx); |
944 | |
945 | |
946 | |
947 | if (State->isNull(ArgVal).isConstrainedTrue()) { |
948 | QualType BTy = getContext().getBaseElementType(DTy); |
949 | const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl(); |
950 | const CXXDestructorDecl *Dtor = RD->getDestructor(); |
951 | |
952 | PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx); |
953 | NodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
954 | Bldr.generateNode(PP, Pred->getState(), Pred); |
955 | return; |
956 | } |
957 | |
958 | EvalCallOptions CallOpts; |
959 | const MemRegion *ArgR = ArgVal.getAsRegion(); |
960 | if (DE->isArrayForm()) { |
961 | |
962 | |
963 | |
964 | CallOpts.IsArrayCtorOrDtor = true; |
965 | |
966 | while (const auto *AT = getContext().getAsArrayType(DTy)) |
967 | DTy = AT->getElementType(); |
968 | if (ArgR) |
969 | ArgR = getStoreManager().GetElementZeroRegion(cast<SubRegion>(ArgR), DTy); |
970 | } |
971 | |
972 | VisitCXXDestructor(DTy, ArgR, DE, , Pred, Dst, CallOpts); |
973 | } |
974 | |
975 | void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, |
976 | ExplodedNode *Pred, ExplodedNodeSet &Dst) { |
977 | const LocationContext *LCtx = Pred->getLocationContext(); |
978 | |
979 | const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); |
980 | Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor, |
981 | LCtx->getStackFrame()); |
982 | SVal ThisVal = Pred->getState()->getSVal(ThisPtr); |
983 | |
984 | |
985 | const CXXBaseSpecifier *Base = D.getBaseSpecifier(); |
986 | QualType BaseTy = Base->getType(); |
987 | SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy, |
988 | Base->isVirtual()); |
989 | |
990 | VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(), |
991 | CurDtor->getBody(), true, Pred, Dst, {}); |
992 | } |
993 | |
994 | void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, |
995 | ExplodedNode *Pred, ExplodedNodeSet &Dst) { |
996 | const FieldDecl *Member = D.getFieldDecl(); |
997 | QualType T = Member->getType(); |
998 | ProgramStateRef State = Pred->getState(); |
999 | const LocationContext *LCtx = Pred->getLocationContext(); |
1000 | |
1001 | const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); |
1002 | Loc ThisVal = getSValBuilder().getCXXThis(CurDtor, |
1003 | LCtx->getStackFrame()); |
1004 | SVal FieldVal = |
1005 | State->getLValue(Member, State->getSVal(ThisVal).castAs<Loc>()); |
1006 | |
1007 | |
1008 | |
1009 | |
1010 | EvalCallOptions CallOpts; |
1011 | FieldVal = makeZeroElementRegion(State, FieldVal, T, |
1012 | CallOpts.IsArrayCtorOrDtor); |
1013 | |
1014 | VisitCXXDestructor(T, FieldVal.castAs<loc::MemRegionVal>().getRegion(), |
1015 | CurDtor->getBody(), , Pred, Dst, CallOpts); |
1016 | } |
1017 | |
1018 | void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, |
1019 | ExplodedNode *Pred, |
1020 | ExplodedNodeSet &Dst) { |
1021 | const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr(); |
1022 | ProgramStateRef State = Pred->getState(); |
1023 | const LocationContext *LC = Pred->getLocationContext(); |
1024 | const MemRegion *MR = nullptr; |
1025 | |
1026 | if (Optional<SVal> V = |
1027 | getObjectUnderConstruction(State, D.getBindTemporaryExpr(), |
1028 | Pred->getLocationContext())) { |
1029 | |
1030 | |
1031 | |
1032 | State = finishObjectConstruction(State, D.getBindTemporaryExpr(), |
1033 | Pred->getLocationContext()); |
1034 | MR = V->getAsRegion(); |
1035 | } |
1036 | |
1037 | |
1038 | |
1039 | if (isDestructorElided(State, BTE, LC)) { |
1040 | State = cleanupElidedDestructor(State, BTE, LC); |
1041 | NodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
1042 | PostImplicitCall PP(D.getDestructorDecl(getContext()), |
1043 | D.getBindTemporaryExpr()->getBeginLoc(), |
1044 | Pred->getLocationContext()); |
1045 | Bldr.generateNode(PP, State, Pred); |
1046 | return; |
1047 | } |
1048 | |
1049 | ExplodedNodeSet CleanDtorState; |
1050 | StmtNodeBuilder StmtBldr(Pred, CleanDtorState, *currBldrCtx); |
1051 | StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State); |
1052 | |
1053 | QualType T = D.getBindTemporaryExpr()->getSubExpr()->getType(); |
1054 | |
1055 | |
1056 | assert(CleanDtorState.size() <= 1); |
1057 | ExplodedNode *CleanPred = |
1058 | CleanDtorState.empty() ? Pred : *CleanDtorState.begin(); |
1059 | |
1060 | EvalCallOptions CallOpts; |
1061 | CallOpts.IsTemporaryCtorOrDtor = true; |
1062 | if (!MR) { |
1063 | CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; |
1064 | |
1065 | |
1066 | |
1067 | |
1068 | while (const ArrayType *AT = getContext().getAsArrayType(T)) { |
1069 | T = AT->getElementType(); |
1070 | CallOpts.IsArrayCtorOrDtor = true; |
1071 | } |
1072 | } else { |
1073 | |
1074 | |
1075 | |
1076 | } |
1077 | VisitCXXDestructor(T, MR, D.getBindTemporaryExpr(), |
1078 | , CleanPred, Dst, CallOpts); |
1079 | } |
1080 | |
1081 | void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, |
1082 | NodeBuilderContext &BldCtx, |
1083 | ExplodedNode *Pred, |
1084 | ExplodedNodeSet &Dst, |
1085 | const CFGBlock *DstT, |
1086 | const CFGBlock *DstF) { |
1087 | BranchNodeBuilder TempDtorBuilder(Pred, Dst, BldCtx, DstT, DstF); |
1088 | ProgramStateRef State = Pred->getState(); |
1089 | const LocationContext *LC = Pred->getLocationContext(); |
1090 | if (getObjectUnderConstruction(State, BTE, LC)) { |
1091 | TempDtorBuilder.markInfeasible(false); |
1092 | TempDtorBuilder.generateNode(State, true, Pred); |
1093 | } else { |
1094 | TempDtorBuilder.markInfeasible(true); |
1095 | TempDtorBuilder.generateNode(State, false, Pred); |
1096 | } |
1097 | } |
1098 | |
1099 | void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, |
1100 | ExplodedNodeSet &PreVisit, |
1101 | ExplodedNodeSet &Dst) { |
1102 | |
1103 | |
1104 | |
1105 | if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) { |
1106 | |
1107 | |
1108 | Dst = PreVisit; |
1109 | return; |
1110 | } |
1111 | StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx); |
1112 | for (ExplodedNode *Node : PreVisit) { |
1113 | ProgramStateRef State = Node->getState(); |
1114 | const LocationContext *LC = Node->getLocationContext(); |
1115 | if (!getObjectUnderConstruction(State, BTE, LC)) { |
1116 | |
1117 | |
1118 | |
1119 | |
1120 | State = addObjectUnderConstruction(State, BTE, LC, UnknownVal()); |
1121 | } |
1122 | StmtBldr.generateNode(BTE, Node, State); |
1123 | } |
1124 | } |
1125 | |
1126 | ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V, |
1127 | PointerEscapeKind K) const { |
1128 | class CollectReachableSymbolsCallback final : public SymbolVisitor { |
1129 | InvalidatedSymbols Symbols; |
1130 | |
1131 | public: |
1132 | explicit CollectReachableSymbolsCallback(ProgramStateRef) {} |
1133 | |
1134 | const InvalidatedSymbols &getSymbols() const { return Symbols; } |
1135 | |
1136 | bool VisitSymbol(SymbolRef Sym) override { |
1137 | Symbols.insert(Sym); |
1138 | return true; |
1139 | } |
1140 | }; |
1141 | |
1142 | const CollectReachableSymbolsCallback &Scanner = |
1143 | State->scanReachableSymbols<CollectReachableSymbolsCallback>(V); |
1144 | return getCheckerManager().runCheckersForPointerEscape( |
1145 | State, Scanner.getSymbols(), nullptr, K, nullptr); |
1146 | } |
1147 | |
1148 | void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, |
1149 | ExplodedNodeSet &DstTop) { |
1150 | PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), |
1151 | S->getBeginLoc(), "Error evaluating statement"); |
1152 | ExplodedNodeSet Dst; |
1153 | StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx); |
1154 | |
1155 | (S) || S == cast(S)->IgnoreParens()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 1155, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens()); |
1156 | |
1157 | switch (S->getStmtClass()) { |
1158 | |
1159 | case Expr::ObjCIndirectCopyRestoreExprClass: |
1160 | case Stmt::CXXDependentScopeMemberExprClass: |
1161 | case Stmt::CXXInheritedCtorInitExprClass: |
1162 | case Stmt::CXXTryStmtClass: |
1163 | case Stmt::CXXTypeidExprClass: |
1164 | case Stmt::CXXUuidofExprClass: |
1165 | case Stmt::CXXFoldExprClass: |
1166 | case Stmt::MSPropertyRefExprClass: |
1167 | case Stmt::MSPropertySubscriptExprClass: |
1168 | case Stmt::CXXUnresolvedConstructExprClass: |
1169 | case Stmt::DependentScopeDeclRefExprClass: |
1170 | case Stmt::ArrayTypeTraitExprClass: |
1171 | case Stmt::ExpressionTraitExprClass: |
1172 | case Stmt::UnresolvedLookupExprClass: |
1173 | case Stmt::UnresolvedMemberExprClass: |
1174 | case Stmt::TypoExprClass: |
1175 | case Stmt::CXXNoexceptExprClass: |
1176 | case Stmt::PackExpansionExprClass: |
1177 | case Stmt::SubstNonTypeTemplateParmPackExprClass: |
1178 | case Stmt::FunctionParmPackExprClass: |
1179 | case Stmt::CoroutineBodyStmtClass: |
1180 | case Stmt::CoawaitExprClass: |
1181 | case Stmt::DependentCoawaitExprClass: |
1182 | case Stmt::CoreturnStmtClass: |
1183 | case Stmt::CoyieldExprClass: |
1184 | case Stmt::SEHTryStmtClass: |
1185 | case Stmt::SEHExceptStmtClass: |
1186 | case Stmt::SEHLeaveStmtClass: |
1187 | case Stmt::SEHFinallyStmtClass: |
1188 | case Stmt::OMPParallelDirectiveClass: |
1189 | case Stmt::OMPSimdDirectiveClass: |
1190 | case Stmt::OMPForDirectiveClass: |
1191 | case Stmt::OMPForSimdDirectiveClass: |
1192 | case Stmt::OMPSectionsDirectiveClass: |
1193 | case Stmt::OMPSectionDirectiveClass: |
1194 | case Stmt::OMPSingleDirectiveClass: |
1195 | case Stmt::OMPMasterDirectiveClass: |
1196 | case Stmt::OMPCriticalDirectiveClass: |
1197 | case Stmt::OMPParallelForDirectiveClass: |
1198 | case Stmt::OMPParallelForSimdDirectiveClass: |
1199 | case Stmt::OMPParallelSectionsDirectiveClass: |
1200 | case Stmt::OMPTaskDirectiveClass: |
1201 | case Stmt::OMPTaskyieldDirectiveClass: |
1202 | case Stmt::OMPBarrierDirectiveClass: |
1203 | case Stmt::OMPTaskwaitDirectiveClass: |
1204 | case Stmt::OMPTaskgroupDirectiveClass: |
1205 | case Stmt::OMPFlushDirectiveClass: |
1206 | case Stmt::OMPOrderedDirectiveClass: |
1207 | case Stmt::OMPAtomicDirectiveClass: |
1208 | case Stmt::OMPTargetDirectiveClass: |
1209 | case Stmt::OMPTargetDataDirectiveClass: |
1210 | case Stmt::OMPTargetEnterDataDirectiveClass: |
1211 | case Stmt::OMPTargetExitDataDirectiveClass: |
1212 | case Stmt::OMPTargetParallelDirectiveClass: |
1213 | case Stmt::OMPTargetParallelForDirectiveClass: |
1214 | case Stmt::OMPTargetUpdateDirectiveClass: |
1215 | case Stmt::OMPTeamsDirectiveClass: |
1216 | case Stmt::OMPCancellationPointDirectiveClass: |
1217 | case Stmt::OMPCancelDirectiveClass: |
1218 | case Stmt::OMPTaskLoopDirectiveClass: |
1219 | case Stmt::OMPTaskLoopSimdDirectiveClass: |
1220 | case Stmt::OMPDistributeDirectiveClass: |
1221 | case Stmt::OMPDistributeParallelForDirectiveClass: |
1222 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: |
1223 | case Stmt::OMPDistributeSimdDirectiveClass: |
1224 | case Stmt::OMPTargetParallelForSimdDirectiveClass: |
1225 | case Stmt::OMPTargetSimdDirectiveClass: |
1226 | case Stmt::OMPTeamsDistributeDirectiveClass: |
1227 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: |
1228 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: |
1229 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: |
1230 | case Stmt::OMPTargetTeamsDirectiveClass: |
1231 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: |
1232 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: |
1233 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: |
1234 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: |
1235 | case Stmt::CapturedStmtClass: { |
1236 | const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); |
1237 | Engine.addAbortedBlock(node, currBldrCtx->getBlock()); |
1238 | break; |
1239 | } |
1240 | |
1241 | case Stmt::ParenExprClass: |
1242 | llvm_unreachable("ParenExprs already handled."); |
1243 | case Stmt::GenericSelectionExprClass: |
1244 | llvm_unreachable("GenericSelectionExprs already handled."); |
1245 | |
1246 | |
1247 | case Stmt::BreakStmtClass: |
1248 | case Stmt::CaseStmtClass: |
1249 | case Stmt::CompoundStmtClass: |
1250 | case Stmt::ContinueStmtClass: |
1251 | case Stmt::CXXForRangeStmtClass: |
1252 | case Stmt::DefaultStmtClass: |
1253 | case Stmt::DoStmtClass: |
1254 | case Stmt::ForStmtClass: |
1255 | case Stmt::GotoStmtClass: |
1256 | case Stmt::IfStmtClass: |
1257 | case Stmt::IndirectGotoStmtClass: |
1258 | case Stmt::LabelStmtClass: |
1259 | case Stmt::NoStmtClass: |
1260 | case Stmt::NullStmtClass: |
1261 | case Stmt::SwitchStmtClass: |
1262 | case Stmt::WhileStmtClass: |
1263 | case Expr::MSDependentExistsStmtClass: |
1264 | llvm_unreachable("Stmt should not be in analyzer evaluation loop"); |
1265 | |
1266 | case Stmt::ObjCSubscriptRefExprClass: |
1267 | case Stmt::ObjCPropertyRefExprClass: |
1268 | llvm_unreachable("These are handled by PseudoObjectExpr"); |
1269 | |
1270 | case Stmt::GNUNullExprClass: { |
1271 | |
1272 | ProgramStateRef state = Pred->getState(); |
1273 | state = state->BindExpr(S, Pred->getLocationContext(), |
1274 | svalBuilder.makeIntValWithPtrWidth(0, false)); |
1275 | Bldr.generateNode(S, Pred, state); |
1276 | break; |
1277 | } |
1278 | |
1279 | case Stmt::ObjCAtSynchronizedStmtClass: |
1280 | Bldr.takeNodes(Pred); |
1281 | VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst); |
1282 | Bldr.addNodes(Dst); |
1283 | break; |
1284 | |
1285 | case Expr::ConstantExprClass: |
1286 | case Stmt::ExprWithCleanupsClass: |
1287 | |
1288 | break; |
1289 | |
1290 | case Stmt::CXXBindTemporaryExprClass: { |
1291 | Bldr.takeNodes(Pred); |
1292 | ExplodedNodeSet PreVisit; |
1293 | getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); |
1294 | ExplodedNodeSet Next; |
1295 | VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next); |
1296 | getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this); |
1297 | Bldr.addNodes(Dst); |
1298 | break; |
1299 | } |
1300 | |
1301 | |
1302 | case Stmt::DesignatedInitExprClass: |
1303 | case Stmt::DesignatedInitUpdateExprClass: |
1304 | case Stmt::ArrayInitLoopExprClass: |
1305 | case Stmt::ArrayInitIndexExprClass: |
1306 | case Stmt::ExtVectorElementExprClass: |
1307 | case Stmt::ImaginaryLiteralClass: |
1308 | case Stmt::ObjCAtCatchStmtClass: |
1309 | case Stmt::ObjCAtFinallyStmtClass: |
1310 | case Stmt::ObjCAtTryStmtClass: |
1311 | case Stmt::ObjCAutoreleasePoolStmtClass: |
1312 | case Stmt::ObjCEncodeExprClass: |
1313 | case Stmt::ObjCIsaExprClass: |
1314 | case Stmt::ObjCProtocolExprClass: |
1315 | case Stmt::ObjCSelectorExprClass: |
1316 | case Stmt::ParenListExprClass: |
1317 | case Stmt::ShuffleVectorExprClass: |
1318 | case Stmt::ConvertVectorExprClass: |
1319 | case Stmt::VAArgExprClass: |
1320 | case Stmt::CUDAKernelCallExprClass: |
1321 | case Stmt::OpaqueValueExprClass: |
1322 | case Stmt::AsTypeExprClass: |
1323 | |
1324 | |
1325 | |
1326 | |
1327 | case Stmt::PredefinedExprClass: |
1328 | case Stmt::AddrLabelExprClass: |
1329 | case Stmt::AttributedStmtClass: |
1330 | case Stmt::IntegerLiteralClass: |
1331 | case Stmt::FixedPointLiteralClass: |
1332 | case Stmt::CharacterLiteralClass: |
1333 | case Stmt::ImplicitValueInitExprClass: |
1334 | case Stmt::CXXScalarValueInitExprClass: |
1335 | case Stmt::CXXBoolLiteralExprClass: |
1336 | case Stmt::ObjCBoolLiteralExprClass: |
1337 | case Stmt::ObjCAvailabilityCheckExprClass: |
1338 | case Stmt::FloatingLiteralClass: |
1339 | case Stmt::NoInitExprClass: |
1340 | case Stmt::SizeOfPackExprClass: |
1341 | case Stmt::StringLiteralClass: |
1342 | case Stmt::ObjCStringLiteralClass: |
1343 | case Stmt::CXXPseudoDestructorExprClass: |
1344 | case Stmt::SubstNonTypeTemplateParmExprClass: |
1345 | case Stmt::CXXNullPtrLiteralExprClass: |
1346 | case Stmt::OMPArraySectionExprClass: |
1347 | case Stmt::TypeTraitExprClass: { |
1348 | Bldr.takeNodes(Pred); |
1349 | ExplodedNodeSet preVisit; |
1350 | getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); |
1351 | getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this); |
1352 | Bldr.addNodes(Dst); |
1353 | break; |
1354 | } |
1355 | |
1356 | case Stmt::CXXDefaultArgExprClass: |
1357 | case Stmt::CXXDefaultInitExprClass: { |
1358 | Bldr.takeNodes(Pred); |
1359 | ExplodedNodeSet PreVisit; |
1360 | getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); |
1361 | |
1362 | ExplodedNodeSet Tmp; |
1363 | StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx); |
1364 | |
1365 | const Expr *ArgE; |
1366 | if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S)) |
1367 | ArgE = DefE->getExpr(); |
1368 | else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S)) |
1369 | ArgE = DefE->getExpr(); |
1370 | else |
1371 | llvm_unreachable("unknown constant wrapper kind"); |
1372 | |
1373 | bool IsTemporary = false; |
1374 | if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) { |
1375 | ArgE = MTE->GetTemporaryExpr(); |
1376 | IsTemporary = true; |
1377 | } |
1378 | |
1379 | Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE); |
1380 | if (!ConstantVal) |
1381 | ConstantVal = UnknownVal(); |
1382 | |
1383 | const LocationContext *LCtx = Pred->getLocationContext(); |
1384 | for (const auto I : PreVisit) { |
1385 | ProgramStateRef State = I->getState(); |
1386 | State = State->BindExpr(S, LCtx, *ConstantVal); |
1387 | if (IsTemporary) |
1388 | State = createTemporaryRegionIfNeeded(State, LCtx, |
1389 | cast<Expr>(S), |
1390 | cast<Expr>(S)); |
1391 | Bldr2.generateNode(S, I, State); |
1392 | } |
1393 | |
1394 | getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); |
1395 | Bldr.addNodes(Dst); |
1396 | break; |
1397 | } |
1398 | |
1399 | |
1400 | case Stmt::CXXStdInitializerListExprClass: |
1401 | case Expr::ObjCArrayLiteralClass: |
1402 | case Expr::ObjCDictionaryLiteralClass: |
1403 | case Expr::ObjCBoxedExprClass: { |
1404 | Bldr.takeNodes(Pred); |
1405 | |
1406 | ExplodedNodeSet preVisit; |
1407 | getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); |
1408 | |
1409 | ExplodedNodeSet Tmp; |
1410 | StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx); |
1411 | |
1412 | const auto *Ex = cast<Expr>(S); |
1413 | QualType resultType = Ex->getType(); |
1414 | |
1415 | for (const auto N : preVisit) { |
1416 | const LocationContext *LCtx = N->getLocationContext(); |
1417 | SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, |
1418 | resultType, |
1419 | currBldrCtx->blockCount()); |
1420 | ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); |
1421 | |
1422 | |
1423 | |
1424 | if (!(isa<ObjCBoxedExpr>(Ex) && |
1425 | !cast<ObjCBoxedExpr>(Ex)->getSubExpr() |
1426 | ->getType()->isRecordType())) |
1427 | for (auto Child : Ex->children()) { |
1428 | assert(Child); |
1429 | SVal Val = State->getSVal(Child, LCtx); |
1430 | State = escapeValue(State, Val, PSK_EscapeOther); |
1431 | } |
1432 | |
1433 | Bldr2.generateNode(S, N, State); |
1434 | } |
1435 | |
1436 | getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); |
1437 | Bldr.addNodes(Dst); |
1438 | break; |
1439 | } |
1440 | |
1441 | case Stmt::ArraySubscriptExprClass: |
1442 | Bldr.takeNodes(Pred); |
1443 | VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst); |
1444 | Bldr.addNodes(Dst); |
1445 | break; |
1446 | |
1447 | case Stmt::GCCAsmStmtClass: |
1448 | Bldr.takeNodes(Pred); |
1449 | VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst); |
1450 | Bldr.addNodes(Dst); |
1451 | break; |
1452 | |
1453 | case Stmt::MSAsmStmtClass: |
1454 | Bldr.takeNodes(Pred); |
1455 | VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst); |
1456 | Bldr.addNodes(Dst); |
1457 | break; |
1458 | |
1459 | case Stmt::BlockExprClass: |
1460 | Bldr.takeNodes(Pred); |
1461 | VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst); |
1462 | Bldr.addNodes(Dst); |
1463 | break; |
1464 | |
1465 | case Stmt::LambdaExprClass: |
1466 | if (AMgr.options.ShouldInlineLambdas) { |
1467 | Bldr.takeNodes(Pred); |
1468 | VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst); |
1469 | Bldr.addNodes(Dst); |
1470 | } else { |
1471 | const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); |
1472 | Engine.addAbortedBlock(node, currBldrCtx->getBlock()); |
1473 | } |
1474 | break; |
1475 | |
1476 | case Stmt::BinaryOperatorClass: { |
1477 | const auto *B = cast<BinaryOperator>(S); |
1478 | if (B->isLogicalOp()) { |
1479 | Bldr.takeNodes(Pred); |
1480 | VisitLogicalExpr(B, Pred, Dst); |
1481 | Bldr.addNodes(Dst); |
1482 | break; |
1483 | } |
1484 | else if (B->getOpcode() == BO_Comma) { |
1485 | ProgramStateRef state = Pred->getState(); |
1486 | Bldr.generateNode(B, Pred, |
1487 | state->BindExpr(B, Pred->getLocationContext(), |
1488 | state->getSVal(B->getRHS(), |
1489 | Pred->getLocationContext()))); |
1490 | break; |
1491 | } |
1492 | |
1493 | Bldr.takeNodes(Pred); |
1494 | |
1495 | if (AMgr.options.ShouldEagerlyAssume && |
1496 | (B->isRelationalOp() || B->isEqualityOp())) { |
1497 | ExplodedNodeSet Tmp; |
1498 | VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp); |
1499 | evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S)); |
1500 | } |
1501 | else |
1502 | VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); |
1503 | |
1504 | Bldr.addNodes(Dst); |
1505 | break; |
1506 | } |
1507 | |
1508 | case Stmt::CXXOperatorCallExprClass: { |
1509 | const auto *OCE = cast<CXXOperatorCallExpr>(S); |
1510 | |
1511 | |
1512 | |
1513 | const Decl *Callee = OCE->getCalleeDecl(); |
1514 | if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) { |
1515 | if (MD->isInstance()) { |
1516 | ProgramStateRef State = Pred->getState(); |
1517 | const LocationContext *LCtx = Pred->getLocationContext(); |
1518 | ProgramStateRef NewState = |
1519 | createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); |
1520 | if (NewState != State) { |
1521 | Pred = Bldr.generateNode(OCE, Pred, NewState, , |
1522 | ProgramPoint::PreStmtKind); |
1523 | |
1524 | if (!Pred) |
1525 | break; |
1526 | } |
1527 | } |
1528 | } |
1529 | |
1530 | LLVM_FALLTHROUGH; |
1531 | } |
1532 | |
1533 | case Stmt::CallExprClass: |
1534 | case Stmt::CXXMemberCallExprClass: |
1535 | case Stmt::UserDefinedLiteralClass: |
1536 | Bldr.takeNodes(Pred); |
1537 | VisitCallExpr(cast<CallExpr>(S), Pred, Dst); |
1538 | Bldr.addNodes(Dst); |
1539 | break; |
1540 | |
1541 | case Stmt::CXXCatchStmtClass: |
1542 | Bldr.takeNodes(Pred); |
1543 | VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst); |
1544 | Bldr.addNodes(Dst); |
1545 | break; |
1546 | |
1547 | case Stmt::CXXTemporaryObjectExprClass: |
1548 | case Stmt::CXXConstructExprClass: |
1549 | Bldr.takeNodes(Pred); |
1550 | VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst); |
1551 | Bldr.addNodes(Dst); |
1552 | break; |
1553 | |
1554 | case Stmt::CXXNewExprClass: { |
1555 | Bldr.takeNodes(Pred); |
1556 | |
1557 | ExplodedNodeSet PreVisit; |
1558 | getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); |
1559 | |
1560 | ExplodedNodeSet PostVisit; |
1561 | for (const auto i : PreVisit) |
1562 | VisitCXXNewExpr(cast<CXXNewExpr>(S), i, PostVisit); |
1563 | |
1564 | getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); |
1565 | Bldr.addNodes(Dst); |
1566 | break; |
1567 | } |
1568 | |
1569 | case Stmt::CXXDeleteExprClass: { |
1570 | Bldr.takeNodes(Pred); |
1571 | ExplodedNodeSet PreVisit; |
1572 | const auto *CDE = cast<CXXDeleteExpr>(S); |
1573 | getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); |
1574 | |
1575 | for (const auto i : PreVisit) |
1576 | VisitCXXDeleteExpr(CDE, i, Dst); |
1577 | |
1578 | Bldr.addNodes(Dst); |
1579 | break; |
1580 | } |
1581 | |
1582 | |
1583 | |
1584 | case Stmt::ChooseExprClass: { |
1585 | Bldr.takeNodes(Pred); |
1586 | const auto *C = cast<ChooseExpr>(S); |
1587 | VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); |
1588 | Bldr.addNodes(Dst); |
1589 | break; |
1590 | } |
1591 | |
1592 | case Stmt::CompoundAssignOperatorClass: |
1593 | Bldr.takeNodes(Pred); |
1594 | VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); |
1595 | Bldr.addNodes(Dst); |
1596 | break; |
1597 | |
1598 | case Stmt::CompoundLiteralExprClass: |
1599 | Bldr.takeNodes(Pred); |
1600 | VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst); |
1601 | Bldr.addNodes(Dst); |
1602 | break; |
1603 | |
1604 | case Stmt::BinaryConditionalOperatorClass: |
1605 | case Stmt::ConditionalOperatorClass: { |
1606 | Bldr.takeNodes(Pred); |
1607 | const auto *C = cast<AbstractConditionalOperator>(S); |
1608 | VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst); |
1609 | Bldr.addNodes(Dst); |
1610 | break; |
1611 | } |
1612 | |
1613 | case Stmt::CXXThisExprClass: |
1614 | Bldr.takeNodes(Pred); |
1615 | VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst); |
1616 | Bldr.addNodes(Dst); |
1617 | break; |
1618 | |
1619 | case Stmt::DeclRefExprClass: { |
1620 | Bldr.takeNodes(Pred); |
1621 | const auto *DE = cast<DeclRefExpr>(S); |
1622 | VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); |
1623 | Bldr.addNodes(Dst); |
1624 | break; |
1625 | } |
1626 | |
1627 | case Stmt::DeclStmtClass: |
1628 | Bldr.takeNodes(Pred); |
1629 | VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); |
1630 | Bldr.addNodes(Dst); |
1631 | break; |
1632 | |
1633 | case Stmt::ImplicitCastExprClass: |
1634 | case Stmt::CStyleCastExprClass: |
1635 | case Stmt::CXXStaticCastExprClass: |
1636 | case Stmt::CXXDynamicCastExprClass: |
1637 | case Stmt::CXXReinterpretCastExprClass: |
1638 | case Stmt::CXXConstCastExprClass: |
1639 | case Stmt::CXXFunctionalCastExprClass: |
1640 | case Stmt::ObjCBridgedCastExprClass: { |
1641 | Bldr.takeNodes(Pred); |
1642 | const auto *C = cast<CastExpr>(S); |
1643 | ExplodedNodeSet dstExpr; |
1644 | VisitCast(C, C->getSubExpr(), Pred, dstExpr); |
1645 | |
1646 | |
1647 | getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this); |
1648 | Bldr.addNodes(Dst); |
1649 | break; |
1650 | } |
1651 | |
1652 | case Expr::MaterializeTemporaryExprClass: { |
1653 | Bldr.takeNodes(Pred); |
1654 | const auto *MTE = cast<MaterializeTemporaryExpr>(S); |
1655 | ExplodedNodeSet dstPrevisit; |
1656 | getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, MTE, *this); |
1657 | ExplodedNodeSet dstExpr; |
1658 | for (const auto i : dstPrevisit) |
1659 | CreateCXXTemporaryObject(MTE, i, dstExpr); |
1660 | getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, MTE, *this); |
1661 | Bldr.addNodes(Dst); |
1662 | break; |
1663 | } |
1664 | |
1665 | case Stmt::InitListExprClass: |
1666 | Bldr.takeNodes(Pred); |
1667 | VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); |
1668 | Bldr.addNodes(Dst); |
1669 | break; |
1670 | |
1671 | case Stmt::MemberExprClass: |
1672 | Bldr.takeNodes(Pred); |
1673 | VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst); |
1674 | Bldr.addNodes(Dst); |
1675 | break; |
1676 | |
1677 | case Stmt::AtomicExprClass: |
1678 | Bldr.takeNodes(Pred); |
1679 | VisitAtomicExpr(cast<AtomicExpr>(S), Pred, Dst); |
1680 | Bldr.addNodes(Dst); |
1681 | break; |
1682 | |
1683 | case Stmt::ObjCIvarRefExprClass: |
1684 | Bldr.takeNodes(Pred); |
1685 | VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst); |
1686 | Bldr.addNodes(Dst); |
1687 | break; |
1688 | |
1689 | case Stmt::ObjCForCollectionStmtClass: |
1690 | Bldr.takeNodes(Pred); |
1691 | VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst); |
1692 | Bldr.addNodes(Dst); |
1693 | break; |
1694 | |
1695 | case Stmt::ObjCMessageExprClass: |
1696 | Bldr.takeNodes(Pred); |
1697 | VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst); |
1698 | Bldr.addNodes(Dst); |
1699 | break; |
1700 | |
1701 | case Stmt::ObjCAtThrowStmtClass: |
1702 | case Stmt::CXXThrowExprClass: |
1703 | |
1704 | |
1705 | Bldr.generateSink(S, Pred, Pred->getState()); |
1706 | break; |
1707 | |
1708 | case Stmt::ReturnStmtClass: |
1709 | Bldr.takeNodes(Pred); |
1710 | VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); |
1711 | Bldr.addNodes(Dst); |
1712 | break; |
1713 | |
1714 | case Stmt::OffsetOfExprClass: { |
1715 | Bldr.takeNodes(Pred); |
1716 | ExplodedNodeSet PreVisit; |
1717 | getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); |
1718 | |
1719 | ExplodedNodeSet PostVisit; |
1720 | for (const auto Node : PreVisit) |
1721 | VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Node, PostVisit); |
1722 | |
1723 | getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); |
1724 | Bldr.addNodes(Dst); |
1725 | break; |
1726 | } |
1727 | |
1728 | case Stmt::UnaryExprOrTypeTraitExprClass: |
1729 | Bldr.takeNodes(Pred); |
1730 | VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), |
1731 | Pred, Dst); |
1732 | Bldr.addNodes(Dst); |
1733 | break; |
1734 | |
1735 | case Stmt::StmtExprClass: { |
1736 | const auto *SE = cast<StmtExpr>(S); |
1737 | |
1738 | if (SE->getSubStmt()->body_empty()) { |
1739 | |
1740 | (0) . __assert_fail ("SE->getType() == getContext().VoidTy && \"Empty statement expression must have void type.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 1741, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(SE->getType() == getContext().VoidTy |
1741 | (0) . __assert_fail ("SE->getType() == getContext().VoidTy && \"Empty statement expression must have void type.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 1741, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> && "Empty statement expression must have void type."); |
1742 | break; |
1743 | } |
1744 | |
1745 | if (const auto *LastExpr = |
1746 | dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { |
1747 | ProgramStateRef state = Pred->getState(); |
1748 | Bldr.generateNode(SE, Pred, |
1749 | state->BindExpr(SE, Pred->getLocationContext(), |
1750 | state->getSVal(LastExpr, |
1751 | Pred->getLocationContext()))); |
1752 | } |
1753 | break; |
1754 | } |
1755 | |
1756 | case Stmt::UnaryOperatorClass: { |
1757 | Bldr.takeNodes(Pred); |
1758 | const auto *U = cast<UnaryOperator>(S); |
1759 | if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) { |
1760 | ExplodedNodeSet Tmp; |
1761 | VisitUnaryOperator(U, Pred, Tmp); |
1762 | evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U); |
1763 | } |
1764 | else |
1765 | VisitUnaryOperator(U, Pred, Dst); |
1766 | Bldr.addNodes(Dst); |
1767 | break; |
1768 | } |
1769 | |
1770 | case Stmt::PseudoObjectExprClass: { |
1771 | Bldr.takeNodes(Pred); |
1772 | ProgramStateRef state = Pred->getState(); |
1773 | const auto *PE = cast<PseudoObjectExpr>(S); |
1774 | if (const Expr *Result = PE->getResultExpr()) { |
1775 | SVal V = state->getSVal(Result, Pred->getLocationContext()); |
1776 | Bldr.generateNode(S, Pred, |
1777 | state->BindExpr(S, Pred->getLocationContext(), V)); |
1778 | } |
1779 | else |
1780 | Bldr.generateNode(S, Pred, |
1781 | state->BindExpr(S, Pred->getLocationContext(), |
1782 | UnknownVal())); |
1783 | |
1784 | Bldr.addNodes(Dst); |
1785 | break; |
1786 | } |
1787 | } |
1788 | } |
1789 | |
1790 | bool ExprEngine::replayWithoutInlining(ExplodedNode *N, |
1791 | const LocationContext *CalleeLC) { |
1792 | const StackFrameContext *CalleeSF = CalleeLC->getStackFrame(); |
1793 | const StackFrameContext *CallerSF = CalleeSF->getParent()->getStackFrame(); |
1794 | assert(CalleeSF && CallerSF); |
1795 | ExplodedNode *BeforeProcessingCall = nullptr; |
1796 | const Stmt *CE = CalleeSF->getCallSite(); |
1797 | |
1798 | |
1799 | while (N) { |
1800 | ProgramPoint L = N->getLocation(); |
1801 | BeforeProcessingCall = N; |
1802 | N = N->pred_empty() ? nullptr : *(N->pred_begin()); |
1803 | |
1804 | |
1805 | if (L.getStackFrame() != CallerSF) |
1806 | continue; |
1807 | |
1808 | |
1809 | if (L.isPurgeKind()) |
1810 | continue; |
1811 | if (L.getAs<PreImplicitCall>()) |
1812 | continue; |
1813 | if (L.getAs<CallEnter>()) |
1814 | continue; |
1815 | if (Optional<StmtPoint> SP = L.getAs<StmtPoint>()) |
1816 | if (SP->getStmt() == CE) |
1817 | continue; |
1818 | break; |
1819 | } |
1820 | |
1821 | if (!BeforeProcessingCall) |
1822 | return false; |
1823 | |
1824 | |
1825 | |
1826 | |
1827 | |
1828 | ProgramPoint NewNodeLoc = |
1829 | EpsilonPoint(BeforeProcessingCall->getLocationContext(), CE); |
1830 | |
1831 | |
1832 | ProgramStateRef NewNodeState = BeforeProcessingCall->getState(); |
1833 | NewNodeState = |
1834 | NewNodeState->set<ReplayWithoutInlining>(const_cast<Stmt *>(CE)); |
1835 | |
1836 | |
1837 | bool IsNew = false; |
1838 | ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew); |
1839 | |
1840 | |
1841 | if (!IsNew) |
1842 | return true; |
1843 | |
1844 | NewNode->addPredecessor(BeforeProcessingCall, G); |
1845 | |
1846 | |
1847 | Engine.enqueueStmtNode(NewNode, CalleeSF->getCallSiteBlock(), |
1848 | CalleeSF->getIndex()); |
1849 | NumTimesRetriedWithoutInlining++; |
1850 | return true; |
1851 | } |
1852 | |
1853 | |
1854 | void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, |
1855 | NodeBuilderWithSinks &nodeBuilder, |
1856 | ExplodedNode *Pred) { |
1857 | PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); |
1858 | |
1859 | |
1860 | if(AMgr.options.ShouldUnrollLoops) { |
1861 | unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath; |
1862 | const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator(); |
1863 | if (Term) { |
1864 | ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(), |
1865 | Pred, maxBlockVisitOnPath); |
1866 | if (NewState != Pred->getState()) { |
1867 | ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred); |
1868 | if (!UpdatedNode) |
1869 | return; |
1870 | Pred = UpdatedNode; |
1871 | } |
1872 | } |
1873 | |
1874 | if(isUnrolledState(Pred->getState())) |
1875 | return; |
1876 | } |
1877 | |
1878 | |
1879 | |
1880 | unsigned int BlockCount = nodeBuilder.getContext().blockCount(); |
1881 | if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 && |
1882 | AMgr.options.ShouldWidenLoops) { |
1883 | const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator(); |
1884 | if (!(Term && |
1885 | (isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term)))) |
1886 | return; |
1887 | |
1888 | const LocationContext *LCtx = Pred->getLocationContext(); |
1889 | ProgramStateRef WidenedState = |
1890 | getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); |
1891 | nodeBuilder.generateNode(WidenedState, Pred); |
1892 | return; |
1893 | } |
1894 | |
1895 | |
1896 | if (BlockCount >= AMgr.options.maxBlockVisitOnPath) { |
1897 | static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); |
1898 | const ExplodedNode *Sink = |
1899 | nodeBuilder.generateSink(Pred->getState(), Pred, &tag); |
1900 | |
1901 | |
1902 | |
1903 | const LocationContext *CalleeLC = Pred->getLocation().getLocationContext(); |
1904 | const LocationContext *CalleeSF = CalleeLC->getStackFrame(); |
1905 | const LocationContext *RootLC = |
1906 | (*G.roots_begin())->getLocation().getLocationContext(); |
1907 | if (RootLC->getStackFrame() != CalleeSF) { |
1908 | Engine.FunctionSummaries->markReachedMaxBlockCount(CalleeSF->getDecl()); |
1909 | |
1910 | |
1911 | |
1912 | |
1913 | |
1914 | if ((!AMgr.options.NoRetryExhausted && |
1915 | replayWithoutInlining(Pred, CalleeLC))) |
1916 | return; |
1917 | NumMaxBlockCountReachedInInlined++; |
1918 | } else |
1919 | NumMaxBlockCountReached++; |
1920 | |
1921 | |
1922 | Engine.blocksExhausted.push_back(std::make_pair(L, Sink)); |
1923 | } |
1924 | } |
1925 | |
1926 | |
1927 | |
1928 | |
1929 | |
1930 | |
1931 | |
1932 | |
1933 | |
1934 | |
1935 | static SVal RecoverCastedSymbol(ProgramStateRef state, |
1936 | const Stmt *Condition, |
1937 | const LocationContext *LCtx, |
1938 | ASTContext &Ctx) { |
1939 | |
1940 | const auto *Ex = dyn_cast<Expr>(Condition); |
1941 | if (!Ex) |
1942 | return UnknownVal(); |
1943 | |
1944 | uint64_t bits = 0; |
1945 | bool bitsInit = false; |
1946 | |
1947 | while (const auto *CE = dyn_cast<CastExpr>(Ex)) { |
1948 | QualType T = CE->getType(); |
1949 | |
1950 | if (!T->isIntegralOrEnumerationType()) |
1951 | return UnknownVal(); |
1952 | |
1953 | uint64_t newBits = Ctx.getTypeSize(T); |
1954 | if (!bitsInit || newBits < bits) { |
1955 | bitsInit = true; |
1956 | bits = newBits; |
1957 | } |
1958 | |
1959 | Ex = CE->getSubExpr(); |
1960 | } |
1961 | |
1962 | |
1963 | QualType T = Ex->getType(); |
1964 | |
1965 | if (!bitsInit || !T->isIntegralOrEnumerationType() || |
1966 | Ctx.getTypeSize(T) > bits) |
1967 | return UnknownVal(); |
1968 | |
1969 | return state->getSVal(Ex, LCtx); |
1970 | } |
1971 | |
1972 | #ifndef NDEBUG |
1973 | static const Stmt *getRightmostLeaf(const Stmt *Condition) { |
1974 | while (Condition) { |
1975 | const auto *BO = dyn_cast<BinaryOperator>(Condition); |
1976 | if (!BO || !BO->isLogicalOp()) { |
1977 | return Condition; |
1978 | } |
1979 | Condition = BO->getRHS()->IgnoreParens(); |
1980 | } |
1981 | return nullptr; |
1982 | } |
1983 | #endif |
1984 | |
1985 | |
1986 | |
1987 | |
1988 | |
1989 | |
1990 | |
1991 | |
1992 | |
1993 | |
1994 | |
1995 | |
1996 | |
1997 | |
1998 | |
1999 | static const Stmt *ResolveCondition(const Stmt *Condition, |
2000 | const CFGBlock *B) { |
2001 | if (const auto *Ex = dyn_cast<Expr>(Condition)) |
2002 | Condition = Ex->IgnoreParens(); |
2003 | |
2004 | const auto *BO = dyn_cast<BinaryOperator>(Condition); |
2005 | if (!BO || !BO->isLogicalOp()) |
2006 | return Condition; |
2007 | |
2008 | (0) . __assert_fail ("!B->getTerminator().isTemporaryDtorsBranch() && \"Temporary destructor branches handled by processBindTemporary.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2009, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!B->getTerminator().isTemporaryDtorsBranch() && |
2009 | (0) . __assert_fail ("!B->getTerminator().isTemporaryDtorsBranch() && \"Temporary destructor branches handled by processBindTemporary.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2009, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Temporary destructor branches handled by processBindTemporary."); |
2010 | |
2011 | |
2012 | |
2013 | |
2014 | |
2015 | |
2016 | |
2017 | |
2018 | |
2019 | CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend(); |
2020 | for (; I != E; ++I) { |
2021 | CFGElement Elem = *I; |
2022 | Optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); |
2023 | if (!CS) |
2024 | continue; |
2025 | const Stmt *LastStmt = CS->getStmt(); |
2026 | assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); |
2027 | return LastStmt; |
2028 | } |
2029 | llvm_unreachable("could not resolve condition"); |
2030 | } |
2031 | |
2032 | void ExprEngine::processBranch(const Stmt *Condition, |
2033 | NodeBuilderContext& BldCtx, |
2034 | ExplodedNode *Pred, |
2035 | ExplodedNodeSet &Dst, |
2036 | const CFGBlock *DstT, |
2037 | const CFGBlock *DstF) { |
2038 | (0) . __assert_fail ("(!Condition || !isa(Condition)) && \"CXXBindTemporaryExprs are handled by processBindTemporary.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2039, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) && |
2039 | (0) . __assert_fail ("(!Condition || !isa(Condition)) && \"CXXBindTemporaryExprs are handled by processBindTemporary.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2039, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "CXXBindTemporaryExprs are handled by processBindTemporary."); |
2040 | const LocationContext *LCtx = Pred->getLocationContext(); |
2041 | PrettyStackTraceLocationContext StackCrashInfo(LCtx); |
2042 | currBldrCtx = &BldCtx; |
2043 | |
2044 | |
2045 | if (!Condition) { |
2046 | BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF); |
2047 | NullCondBldr.markInfeasible(false); |
2048 | NullCondBldr.generateNode(Pred->getState(), true, Pred); |
2049 | return; |
2050 | } |
2051 | |
2052 | if (const auto *Ex = dyn_cast<Expr>(Condition)) |
2053 | Condition = Ex->IgnoreParens(); |
2054 | |
2055 | Condition = ResolveCondition(Condition, BldCtx.getBlock()); |
2056 | PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), |
2057 | Condition->getBeginLoc(), |
2058 | "Error evaluating branch"); |
2059 | |
2060 | ExplodedNodeSet CheckersOutSet; |
2061 | getCheckerManager().runCheckersForBranchCondition(Condition, CheckersOutSet, |
2062 | Pred, *this); |
2063 | |
2064 | if (CheckersOutSet.empty()) |
2065 | return; |
2066 | |
2067 | BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF); |
2068 | for (const auto PredI : CheckersOutSet) { |
2069 | if (PredI->isSink()) |
2070 | continue; |
2071 | |
2072 | ProgramStateRef PrevState = PredI->getState(); |
2073 | SVal X = PrevState->getSVal(Condition, PredI->getLocationContext()); |
2074 | |
2075 | if (X.isUnknownOrUndef()) { |
2076 | |
2077 | if (const auto *Ex = dyn_cast<Expr>(Condition)) { |
2078 | if (Ex->getType()->isIntegralOrEnumerationType()) { |
2079 | |
2080 | |
2081 | |
2082 | |
2083 | SVal recovered = RecoverCastedSymbol(PrevState, Condition, |
2084 | PredI->getLocationContext(), |
2085 | getContext()); |
2086 | |
2087 | if (!recovered.isUnknown()) { |
2088 | X = recovered; |
2089 | } |
2090 | } |
2091 | } |
2092 | } |
2093 | |
2094 | |
2095 | if (X.isUnknownOrUndef()) { |
2096 | builder.generateNode(PrevState, true, PredI); |
2097 | builder.generateNode(PrevState, false, PredI); |
2098 | continue; |
2099 | } |
2100 | |
2101 | DefinedSVal V = X.castAs<DefinedSVal>(); |
2102 | |
2103 | ProgramStateRef StTrue, StFalse; |
2104 | std::tie(StTrue, StFalse) = PrevState->assume(V); |
2105 | |
2106 | |
2107 | if (builder.isFeasible(true)) { |
2108 | if (StTrue) |
2109 | builder.generateNode(StTrue, true, PredI); |
2110 | else |
2111 | builder.markInfeasible(true); |
2112 | } |
2113 | |
2114 | |
2115 | if (builder.isFeasible(false)) { |
2116 | if (StFalse) |
2117 | builder.generateNode(StFalse, false, PredI); |
2118 | else |
2119 | builder.markInfeasible(false); |
2120 | } |
2121 | } |
2122 | currBldrCtx = nullptr; |
2123 | } |
2124 | |
2125 | |
2126 | |
2127 | REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet, |
2128 | llvm::ImmutableSet<const VarDecl *>) |
2129 | |
2130 | void ExprEngine::processStaticInitializer(const DeclStmt *DS, |
2131 | NodeBuilderContext &BuilderCtx, |
2132 | ExplodedNode *Pred, |
2133 | ExplodedNodeSet &Dst, |
2134 | const CFGBlock *DstT, |
2135 | const CFGBlock *DstF) { |
2136 | PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); |
2137 | currBldrCtx = &BuilderCtx; |
2138 | |
2139 | const auto *VD = cast<VarDecl>(DS->getSingleDecl()); |
2140 | ProgramStateRef state = Pred->getState(); |
2141 | bool initHasRun = state->contains<InitializedGlobalsSet>(VD); |
2142 | BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF); |
2143 | |
2144 | if (!initHasRun) { |
2145 | state = state->add<InitializedGlobalsSet>(VD); |
2146 | } |
2147 | |
2148 | builder.generateNode(state, initHasRun, Pred); |
2149 | builder.markInfeasible(!initHasRun); |
2150 | |
2151 | currBldrCtx = nullptr; |
2152 | } |
2153 | |
2154 | |
2155 | |
2156 | void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { |
2157 | ProgramStateRef state = builder.getState(); |
2158 | SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext()); |
2159 | |
2160 | |
2161 | |
2162 | |
2163 | |
2164 | |
2165 | |
2166 | |
2167 | using iterator = IndirectGotoNodeBuilder::iterator; |
2168 | |
2169 | if (Optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) { |
2170 | const LabelDecl *L = LV->getLabel(); |
2171 | |
2172 | for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) { |
2173 | if (I.getLabel() == L) { |
2174 | builder.generateNode(I, state); |
2175 | return; |
2176 | } |
2177 | } |
2178 | |
2179 | llvm_unreachable("No block with label."); |
2180 | } |
2181 | |
2182 | if (V.getAs<loc::ConcreteInt>() || V.getAs<UndefinedVal>()) { |
2183 | |
2184 | |
2185 | |
2186 | |
2187 | return; |
2188 | } |
2189 | |
2190 | |
2191 | |
2192 | |
2193 | for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) |
2194 | builder.generateNode(I, state); |
2195 | } |
2196 | |
2197 | void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC, |
2198 | ExplodedNode *Pred, |
2199 | ExplodedNodeSet &Dst, |
2200 | const BlockEdge &L) { |
2201 | SaveAndRestore<const NodeBuilderContext *> (currBldrCtx, &BC); |
2202 | getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, *this); |
2203 | } |
2204 | |
2205 | |
2206 | |
2207 | void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, |
2208 | ExplodedNode *Pred, |
2209 | const ReturnStmt *RS) { |
2210 | ProgramStateRef State = Pred->getState(); |
2211 | |
2212 | if (!Pred->getStackFrame()->inTopFrame()) |
2213 | State = finishArgumentConstruction( |
2214 | State, *getStateManager().getCallEventManager().getCaller( |
2215 | Pred->getStackFrame(), Pred->getState())); |
2216 | |
2217 | |
2218 | |
2219 | |
2220 | |
2221 | |
2222 | |
2223 | |
2224 | { |
2225 | const LocationContext *FromLC = Pred->getLocationContext(); |
2226 | const LocationContext *ToLC = FromLC->getStackFrame()->getParent(); |
2227 | const LocationContext *LC = FromLC; |
2228 | while (LC != ToLC) { |
2229 | (0) . __assert_fail ("LC && \"ToLC must be a parent of FromLC!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2229, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(LC && "ToLC must be a parent of FromLC!"); |
2230 | for (auto I : State->get<ObjectsUnderConstruction>()) |
2231 | if (I.first.getLocationContext() == LC) { |
2232 | |
2233 | |
2234 | |
2235 | assert(I.first.getItem().getKind() == |
2236 | ConstructionContextItem::TemporaryDestructorKind || |
2237 | I.first.getItem().getKind() == |
2238 | ConstructionContextItem::ElidedDestructorKind); |
2239 | State = State->remove<ObjectsUnderConstruction>(I.first); |
2240 | } |
2241 | LC = LC->getParent(); |
2242 | } |
2243 | } |
2244 | |
2245 | |
2246 | if (State != Pred->getState()) { |
2247 | ExplodedNodeSet PostCleanup; |
2248 | NodeBuilder Bldr(Pred, PostCleanup, BC); |
2249 | Pred = Bldr.generateNode(Pred->getLocation(), State, Pred); |
2250 | if (!Pred) { |
2251 | |
2252 | |
2253 | return; |
2254 | } |
2255 | } |
2256 | |
2257 | getState(), Pred->getLocationContext(), Pred->getStackFrame()->getParent())", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2259, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(areAllObjectsFullyConstructed(Pred->getState(), |
2258 | getState(), Pred->getLocationContext(), Pred->getStackFrame()->getParent())", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2259, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Pred->getLocationContext(), |
2259 | getState(), Pred->getLocationContext(), Pred->getStackFrame()->getParent())", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2259, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Pred->getStackFrame()->getParent())); |
2260 | |
2261 | PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); |
2262 | StateMgr.EndPath(Pred->getState()); |
2263 | |
2264 | ExplodedNodeSet Dst; |
2265 | if (Pred->getLocationContext()->inTopFrame()) { |
2266 | |
2267 | ExplodedNodeSet AfterRemovedDead; |
2268 | removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead); |
2269 | |
2270 | |
2271 | for (const auto I : AfterRemovedDead) |
2272 | getCheckerManager().runCheckersForEndFunction(BC, Dst, I, *this, RS); |
2273 | } else { |
2274 | getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this, RS); |
2275 | } |
2276 | |
2277 | Engine.enqueueEndOfFunction(Dst, RS); |
2278 | } |
2279 | |
2280 | |
2281 | |
2282 | void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { |
2283 | using iterator = SwitchNodeBuilder::iterator; |
2284 | |
2285 | ProgramStateRef state = builder.getState(); |
2286 | const Expr *CondE = builder.getCondition(); |
2287 | SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext()); |
2288 | |
2289 | if (CondV_untested.isUndef()) { |
2290 | |
2291 | |
2292 | |
2293 | |
2294 | return; |
2295 | } |
2296 | DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>(); |
2297 | |
2298 | ProgramStateRef DefaultSt = state; |
2299 | |
2300 | iterator I = builder.begin(), EI = builder.end(); |
2301 | bool defaultIsFeasible = I == EI; |
2302 | |
2303 | for ( ; I != EI; ++I) { |
2304 | |
2305 | if (!I.getBlock()) |
2306 | continue; |
2307 | |
2308 | const CaseStmt *Case = I.getCase(); |
2309 | |
2310 | |
2311 | llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext()); |
2312 | getType())", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2312, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType())); |
2313 | |
2314 | |
2315 | llvm::APSInt V2; |
2316 | if (const Expr *E = Case->getRHS()) |
2317 | V2 = E->EvaluateKnownConstInt(getContext()); |
2318 | else |
2319 | V2 = V1; |
2320 | |
2321 | ProgramStateRef StateCase; |
2322 | if (Optional<NonLoc> NL = CondV.getAs<NonLoc>()) |
2323 | std::tie(StateCase, DefaultSt) = |
2324 | DefaultSt->assumeInclusiveRange(*NL, V1, V2); |
2325 | else |
2326 | StateCase = DefaultSt; |
2327 | |
2328 | if (StateCase) |
2329 | builder.generateCaseStmtNode(I, StateCase); |
2330 | |
2331 | |
2332 | |
2333 | if (DefaultSt) |
2334 | defaultIsFeasible = true; |
2335 | else { |
2336 | defaultIsFeasible = false; |
2337 | break; |
2338 | } |
2339 | } |
2340 | |
2341 | if (!defaultIsFeasible) |
2342 | return; |
2343 | |
2344 | |
2345 | |
2346 | |
2347 | |
2348 | |
2349 | |
2350 | |
2351 | const SwitchStmt *SS = builder.getSwitch(); |
2352 | const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts(); |
2353 | if (CondExpr->getType()->getAs<EnumType>()) { |
2354 | if (SS->isAllEnumCasesCovered()) |
2355 | return; |
2356 | } |
2357 | |
2358 | builder.generateDefaultCaseNode(DefaultSt); |
2359 | } |
2360 | |
2361 | |
2362 | |
2363 | |
2364 | |
2365 | void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, |
2366 | ExplodedNode *Pred, |
2367 | ExplodedNodeSet &Dst) { |
2368 | StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
2369 | |
2370 | ProgramStateRef state = Pred->getState(); |
2371 | const LocationContext *LCtx = Pred->getLocationContext(); |
2372 | |
2373 | if (const auto *VD = dyn_cast<VarDecl>(D)) { |
2374 | |
2375 | |
2376 | isGLValue() || VD->getType()->isVoidType()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2376, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Ex->isGLValue() || VD->getType()->isVoidType()); |
2377 | const LocationContext *LocCtxt = Pred->getLocationContext(); |
2378 | const Decl *D = LocCtxt->getDecl(); |
2379 | const auto *MD = dyn_cast_or_null<CXXMethodDecl>(D); |
2380 | const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex); |
2381 | Optional<std::pair<SVal, QualType>> VInfo; |
2382 | |
2383 | if (AMgr.options.ShouldInlineLambdas && DeclRefEx && |
2384 | DeclRefEx->refersToEnclosingVariableOrCapture() && MD && |
2385 | MD->getParent()->isLambda()) { |
2386 | |
2387 | const CXXRecordDecl *CXXRec = MD->getParent(); |
2388 | llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields; |
2389 | FieldDecl *LambdaThisCaptureField; |
2390 | CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); |
2391 | |
2392 | |
2393 | |
2394 | if (const FieldDecl *FD = LambdaCaptureFields[VD]) { |
2395 | Loc CXXThis = |
2396 | svalBuilder.getCXXThis(MD, LocCtxt->getStackFrame()); |
2397 | SVal CXXThisVal = state->getSVal(CXXThis); |
2398 | VInfo = std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType()); |
2399 | } |
2400 | } |
2401 | |
2402 | if (!VInfo) |
2403 | VInfo = std::make_pair(state->getLValue(VD, LocCtxt), VD->getType()); |
2404 | |
2405 | SVal V = VInfo->first; |
2406 | bool IsReference = VInfo->second->isReferenceType(); |
2407 | |
2408 | |
2409 | |
2410 | if (IsReference) { |
2411 | if (const MemRegion *R = V.getAsRegion()) |
2412 | V = state->getSVal(R); |
2413 | else |
2414 | V = UnknownVal(); |
2415 | } |
2416 | |
2417 | Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, |
2418 | ProgramPoint::PostLValueKind); |
2419 | return; |
2420 | } |
2421 | if (const auto *ED = dyn_cast<EnumConstantDecl>(D)) { |
2422 | isGLValue()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2422, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!Ex->isGLValue()); |
2423 | SVal V = svalBuilder.makeIntVal(ED->getInitVal()); |
2424 | Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V)); |
2425 | return; |
2426 | } |
2427 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
2428 | SVal V = svalBuilder.getFunctionPointer(FD); |
2429 | Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, |
2430 | ProgramPoint::PostLValueKind); |
2431 | return; |
2432 | } |
2433 | if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) { |
2434 | |
2435 | |
2436 | |
2437 | |
2438 | |
2439 | SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, |
2440 | currBldrCtx->blockCount()); |
2441 | state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); |
2442 | Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, |
2443 | ProgramPoint::PostLValueKind); |
2444 | return; |
2445 | } |
2446 | if (isa<BindingDecl>(D)) { |
2447 | |
2448 | |
2449 | return; |
2450 | } |
2451 | |
2452 | llvm_unreachable("Support for this Decl not implemented."); |
2453 | } |
2454 | |
2455 | |
2456 | void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, |
2457 | ExplodedNode *Pred, |
2458 | ExplodedNodeSet &Dst){ |
2459 | const Expr *Base = A->getBase()->IgnoreParens(); |
2460 | const Expr *Idx = A->getIdx()->IgnoreParens(); |
2461 | |
2462 | ExplodedNodeSet CheckerPreStmt; |
2463 | getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this); |
2464 | |
2465 | ExplodedNodeSet EvalSet; |
2466 | StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); |
2467 | |
2468 | bool IsVectorType = A->getBase()->getType()->isVectorType(); |
2469 | |
2470 | |
2471 | |
2472 | |
2473 | bool IsGLValueLike = A->isGLValue() || |
2474 | (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus); |
2475 | |
2476 | for (auto *Node : CheckerPreStmt) { |
2477 | const LocationContext *LCtx = Node->getLocationContext(); |
2478 | ProgramStateRef state = Node->getState(); |
2479 | |
2480 | if (IsGLValueLike) { |
2481 | QualType T = A->getType(); |
2482 | |
2483 | |
2484 | |
2485 | |
2486 | if (T->isVoidType()) |
2487 | T = getContext().CharTy; |
2488 | |
2489 | SVal V = state->getLValue(T, |
2490 | state->getSVal(Idx, LCtx), |
2491 | state->getSVal(Base, LCtx)); |
2492 | Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, |
2493 | ProgramPoint::PostLValueKind); |
2494 | } else if (IsVectorType) { |
2495 | |
2496 | Bldr.generateNode(A, Node, state, nullptr); |
2497 | } else { |
2498 | llvm_unreachable("Array subscript should be an lValue when not \ |
2499 | a vector and not a forbidden lvalue type"); |
2500 | } |
2501 | } |
2502 | |
2503 | getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this); |
2504 | } |
2505 | |
2506 | |
2507 | void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, |
2508 | ExplodedNodeSet &Dst) { |
2509 | |
2510 | ExplodedNodeSet CheckedSet; |
2511 | getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); |
2512 | |
2513 | ExplodedNodeSet EvalSet; |
2514 | ValueDecl *Member = M->getMemberDecl(); |
2515 | |
2516 | |
2517 | |
2518 | if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { |
2519 | for (const auto I : CheckedSet) |
2520 | VisitCommonDeclRefExpr(M, Member, I, EvalSet); |
2521 | } else { |
2522 | StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); |
2523 | ExplodedNodeSet Tmp; |
2524 | |
2525 | for (const auto I : CheckedSet) { |
2526 | ProgramStateRef state = I->getState(); |
2527 | const LocationContext *LCtx = I->getLocationContext(); |
2528 | Expr *BaseExpr = M->getBase(); |
2529 | |
2530 | |
2531 | if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) { |
2532 | if (MD->isInstance()) |
2533 | state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); |
2534 | |
2535 | SVal MDVal = svalBuilder.getFunctionPointer(MD); |
2536 | state = state->BindExpr(M, LCtx, MDVal); |
2537 | |
2538 | Bldr.generateNode(M, I, state); |
2539 | continue; |
2540 | } |
2541 | |
2542 | |
2543 | const SubRegion *MR = nullptr; |
2544 | state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr, |
2545 | , |
2546 | &MR); |
2547 | SVal baseExprVal = |
2548 | MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx); |
2549 | |
2550 | const auto *field = cast<FieldDecl>(Member); |
2551 | SVal L = state->getLValue(field, baseExprVal); |
2552 | |
2553 | if (M->isGLValue() || M->getType()->isArrayType()) { |
2554 | |
2555 | |
2556 | |
2557 | |
2558 | if (!M->isGLValue()) { |
2559 | getType()->isArrayType()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2559, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(M->getType()->isArrayType()); |
2560 | const auto *PE = |
2561 | dyn_cast<ImplicitCastExpr>(I->getParentMap().getParentIgnoreParens(M)); |
2562 | if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { |
2563 | llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); |
2564 | } |
2565 | } |
2566 | |
2567 | if (field->getType()->isReferenceType()) { |
2568 | if (const MemRegion *R = L.getAsRegion()) |
2569 | L = state->getSVal(R); |
2570 | else |
2571 | L = UnknownVal(); |
2572 | } |
2573 | |
2574 | Bldr.generateNode(M, I, state->BindExpr(M, LCtx, L), nullptr, |
2575 | ProgramPoint::PostLValueKind); |
2576 | } else { |
2577 | Bldr.takeNodes(I); |
2578 | evalLoad(Tmp, M, M, I, state, L); |
2579 | Bldr.addNodes(Tmp); |
2580 | } |
2581 | } |
2582 | } |
2583 | |
2584 | getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); |
2585 | } |
2586 | |
2587 | void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, |
2588 | ExplodedNodeSet &Dst) { |
2589 | ExplodedNodeSet AfterPreSet; |
2590 | getCheckerManager().runCheckersForPreStmt(AfterPreSet, Pred, AE, *this); |
2591 | |
2592 | |
2593 | |
2594 | |
2595 | ExplodedNodeSet AfterInvalidateSet; |
2596 | StmtNodeBuilder Bldr(AfterPreSet, AfterInvalidateSet, *currBldrCtx); |
2597 | |
2598 | for (const auto I : AfterPreSet) { |
2599 | ProgramStateRef State = I->getState(); |
2600 | const LocationContext *LCtx = I->getLocationContext(); |
2601 | |
2602 | SmallVector<SVal, 8> ValuesToInvalidate; |
2603 | for (unsigned SI = 0, Count = AE->getNumSubExprs(); SI != Count; SI++) { |
2604 | const Expr *SubExpr = AE->getSubExprs()[SI]; |
2605 | SVal SubExprVal = State->getSVal(SubExpr, LCtx); |
2606 | ValuesToInvalidate.push_back(SubExprVal); |
2607 | } |
2608 | |
2609 | State = State->invalidateRegions(ValuesToInvalidate, AE, |
2610 | currBldrCtx->blockCount(), |
2611 | LCtx, |
2612 | , |
2613 | ); |
2614 | |
2615 | SVal ResultVal = UnknownVal(); |
2616 | State = State->BindExpr(AE, LCtx, ResultVal); |
2617 | Bldr.generateNode(AE, I, State, nullptr, |
2618 | ProgramPoint::PostStmtKind); |
2619 | } |
2620 | |
2621 | getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this); |
2622 | } |
2623 | |
2624 | |
2625 | |
2626 | |
2627 | |
2628 | |
2629 | ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, |
2630 | SVal Loc, |
2631 | SVal Val, |
2632 | const LocationContext *LCtx) { |
2633 | |
2634 | bool escapes = true; |
2635 | |
2636 | |
2637 | if (Optional<loc::MemRegionVal> regionLoc = Loc.getAs<loc::MemRegionVal>()) { |
2638 | escapes = !regionLoc->getRegion()->hasStackStorage(); |
2639 | |
2640 | if (!escapes) { |
2641 | |
2642 | |
2643 | |
2644 | |
2645 | |
2646 | SVal StoredVal = State->getSVal(regionLoc->getRegion()); |
2647 | if (StoredVal != Val) |
2648 | escapes = (State == (State->bindLoc(*regionLoc, Val, LCtx))); |
2649 | } |
2650 | } |
2651 | |
2652 | |
2653 | |
2654 | |
2655 | if (!escapes) |
2656 | return State; |
2657 | |
2658 | |
2659 | |
2660 | State = escapeValue(State, Val, PSK_EscapeOnBind); |
2661 | return State; |
2662 | } |
2663 | |
2664 | ProgramStateRef |
2665 | ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, |
2666 | const InvalidatedSymbols *Invalidated, |
2667 | ArrayRef<const MemRegion *> ExplicitRegions, |
2668 | const CallEvent *Call, |
2669 | RegionAndSymbolInvalidationTraits &ITraits) { |
2670 | if (!Invalidated || Invalidated->empty()) |
2671 | return State; |
2672 | |
2673 | if (!Call) |
2674 | return getCheckerManager().runCheckersForPointerEscape(State, |
2675 | *Invalidated, |
2676 | nullptr, |
2677 | PSK_EscapeOther, |
2678 | &ITraits); |
2679 | |
2680 | |
2681 | |
2682 | InvalidatedSymbols SymbolsDirectlyInvalidated; |
2683 | for (const auto I : ExplicitRegions) { |
2684 | if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>()) |
2685 | SymbolsDirectlyInvalidated.insert(R->getSymbol()); |
2686 | } |
2687 | |
2688 | InvalidatedSymbols SymbolsIndirectlyInvalidated; |
2689 | for (const auto &sym : *Invalidated) { |
2690 | if (SymbolsDirectlyInvalidated.count(sym)) |
2691 | continue; |
2692 | SymbolsIndirectlyInvalidated.insert(sym); |
2693 | } |
2694 | |
2695 | if (!SymbolsDirectlyInvalidated.empty()) |
2696 | State = getCheckerManager().runCheckersForPointerEscape(State, |
2697 | SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall, &ITraits); |
2698 | |
2699 | |
2700 | if (!SymbolsIndirectlyInvalidated.empty()) |
2701 | State = getCheckerManager().runCheckersForPointerEscape(State, |
2702 | SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall, &ITraits); |
2703 | |
2704 | return State; |
2705 | } |
2706 | |
2707 | |
2708 | |
2709 | void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, |
2710 | ExplodedNode *Pred, |
2711 | SVal location, SVal Val, |
2712 | bool atDeclInit, const ProgramPoint *PP) { |
2713 | const LocationContext *LC = Pred->getLocationContext(); |
2714 | PostStmt PS(StoreE, LC); |
2715 | if (!PP) |
2716 | PP = &PS; |
2717 | |
2718 | |
2719 | ExplodedNodeSet CheckedSet; |
2720 | getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, |
2721 | StoreE, *this, *PP); |
2722 | |
2723 | StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx); |
2724 | |
2725 | |
2726 | |
2727 | if (!location.getAs<Loc>()) { |
2728 | const ProgramPoint L = PostStore(StoreE, LC, , |
2729 | ); |
2730 | ProgramStateRef state = Pred->getState(); |
2731 | state = processPointerEscapedOnBind(state, location, Val, LC); |
2732 | Bldr.generateNode(L, state, Pred); |
2733 | return; |
2734 | } |
2735 | |
2736 | for (const auto PredI : CheckedSet) { |
2737 | ProgramStateRef state = PredI->getState(); |
2738 | |
2739 | state = processPointerEscapedOnBind(state, location, Val, LC); |
2740 | |
2741 | |
2742 | |
2743 | |
2744 | state = state->bindLoc(location.castAs<Loc>(), |
2745 | Val, LC, !atDeclInit); |
2746 | |
2747 | const MemRegion *LocReg = nullptr; |
2748 | if (Optional<loc::MemRegionVal> LocRegVal = |
2749 | location.getAs<loc::MemRegionVal>()) { |
2750 | LocReg = LocRegVal->getRegion(); |
2751 | } |
2752 | |
2753 | const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr); |
2754 | Bldr.generateNode(L, state, PredI); |
2755 | } |
2756 | } |
2757 | |
2758 | |
2759 | |
2760 | |
2761 | |
2762 | |
2763 | |
2764 | |
2765 | |
2766 | void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, |
2767 | const Expr *LocationE, |
2768 | ExplodedNode *Pred, |
2769 | ProgramStateRef state, SVal location, SVal Val, |
2770 | const ProgramPointTag *tag) { |
2771 | |
2772 | |
2773 | const Expr *StoreE = AssignE ? AssignE : LocationE; |
2774 | |
2775 | |
2776 | ExplodedNodeSet Tmp; |
2777 | evalLocation(Tmp, AssignE, LocationE, Pred, state, location, false); |
2778 | |
2779 | if (Tmp.empty()) |
2780 | return; |
2781 | |
2782 | if (location.isUndef()) |
2783 | return; |
2784 | |
2785 | for (const auto I : Tmp) |
2786 | evalBind(Dst, StoreE, I, location, Val, false); |
2787 | } |
2788 | |
2789 | void ExprEngine::evalLoad(ExplodedNodeSet &Dst, |
2790 | const Expr *NodeEx, |
2791 | const Expr *BoundEx, |
2792 | ExplodedNode *Pred, |
2793 | ProgramStateRef state, |
2794 | SVal location, |
2795 | const ProgramPointTag *tag, |
2796 | QualType LoadTy) { |
2797 | (0) . __assert_fail ("!location.getAs() && \"location cannot be a NonLoc.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2797, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!location.getAs<NonLoc>() && "location cannot be a NonLoc."); |
2798 | assert(NodeEx); |
2799 | assert(BoundEx); |
2800 | |
2801 | ExplodedNodeSet Tmp; |
2802 | evalLocation(Tmp, NodeEx, BoundEx, Pred, state, location, true); |
2803 | if (Tmp.empty()) |
2804 | return; |
2805 | |
2806 | StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx); |
2807 | if (location.isUndef()) |
2808 | return; |
2809 | |
2810 | |
2811 | for (const auto I : Tmp) { |
2812 | state = I->getState(); |
2813 | const LocationContext *LCtx = I->getLocationContext(); |
2814 | |
2815 | SVal V = UnknownVal(); |
2816 | if (location.isValid()) { |
2817 | if (LoadTy.isNull()) |
2818 | LoadTy = BoundEx->getType(); |
2819 | V = state->getSVal(location.castAs<Loc>(), LoadTy); |
2820 | } |
2821 | |
2822 | Bldr.generateNode(NodeEx, I, state->BindExpr(BoundEx, LCtx, V), tag, |
2823 | ProgramPoint::PostLoadKind); |
2824 | } |
2825 | } |
2826 | |
2827 | void ExprEngine::evalLocation(ExplodedNodeSet &Dst, |
2828 | const Stmt *NodeEx, |
2829 | const Stmt *BoundEx, |
2830 | ExplodedNode *Pred, |
2831 | ProgramStateRef state, |
2832 | SVal location, |
2833 | bool isLoad) { |
2834 | StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx); |
2835 | |
2836 | if (location.isUnknown()) { |
2837 | return; |
2838 | } |
2839 | |
2840 | ExplodedNodeSet Src; |
2841 | BldrTop.takeNodes(Pred); |
2842 | StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx); |
2843 | if (Pred->getState() != state) { |
2844 | |
2845 | |
2846 | |
2847 | |
2848 | |
2849 | |
2850 | |
2851 | |
2852 | |
2853 | static SimpleProgramPointTag tag(TagProviderName, "Location"); |
2854 | Bldr.generateNode(NodeEx, Pred, state, &tag); |
2855 | } |
2856 | ExplodedNodeSet Tmp; |
2857 | getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, |
2858 | NodeEx, BoundEx, *this); |
2859 | BldrTop.addNodes(Tmp); |
2860 | } |
2861 | |
2862 | std::pair<const ProgramPointTag *, const ProgramPointTag*> |
2863 | ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { |
2864 | static SimpleProgramPointTag |
2865 | eagerlyAssumeBinOpBifurcationTrue(TagProviderName, |
2866 | "Eagerly Assume True"), |
2867 | eagerlyAssumeBinOpBifurcationFalse(TagProviderName, |
2868 | "Eagerly Assume False"); |
2869 | return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, |
2870 | &eagerlyAssumeBinOpBifurcationFalse); |
2871 | } |
2872 | |
2873 | void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, |
2874 | ExplodedNodeSet &Src, |
2875 | const Expr *Ex) { |
2876 | StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx); |
2877 | |
2878 | for (const auto Pred : Src) { |
2879 | |
2880 | |
2881 | |
2882 | ProgramPoint P = Pred->getLocation(); |
2883 | if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) { |
2884 | continue; |
2885 | } |
2886 | |
2887 | ProgramStateRef state = Pred->getState(); |
2888 | SVal V = state->getSVal(Ex, Pred->getLocationContext()); |
2889 | Optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>(); |
2890 | if (SEV && SEV->isExpression()) { |
2891 | const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags = |
2892 | geteagerlyAssumeBinOpBifurcationTags(); |
2893 | |
2894 | ProgramStateRef StateTrue, StateFalse; |
2895 | std::tie(StateTrue, StateFalse) = state->assume(*SEV); |
2896 | |
2897 | |
2898 | if (StateTrue) { |
2899 | SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); |
2900 | StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val); |
2901 | Bldr.generateNode(Ex, Pred, StateTrue, tags.first); |
2902 | } |
2903 | |
2904 | |
2905 | if (StateFalse) { |
2906 | SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); |
2907 | StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val); |
2908 | Bldr.generateNode(Ex, Pred, StateFalse, tags.second); |
2909 | } |
2910 | } |
2911 | } |
2912 | } |
2913 | |
2914 | void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, |
2915 | ExplodedNodeSet &Dst) { |
2916 | StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
2917 | |
2918 | |
2919 | |
2920 | |
2921 | |
2922 | |
2923 | |
2924 | ProgramStateRef state = Pred->getState(); |
2925 | |
2926 | for (const Expr *O : A->outputs()) { |
2927 | SVal X = state->getSVal(O, Pred->getLocationContext()); |
2928 | ()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp", 2928, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!X.getAs<NonLoc>()); |
2929 | |
2930 | if (Optional<Loc> LV = X.getAs<Loc>()) |
2931 | state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext()); |
2932 | } |
2933 | |
2934 | Bldr.generateNode(A, Pred, state); |
2935 | } |
2936 | |
2937 | void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred, |
2938 | ExplodedNodeSet &Dst) { |
2939 | StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); |
2940 | Bldr.generateNode(A, Pred, Pred->getState()); |
2941 | } |
2942 | |
2943 | |
2944 | |
2945 | |
2946 | |
2947 | #ifndef NDEBUG |
2948 | namespace llvm { |
2949 | |
2950 | template<> |
2951 | struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { |
2952 | DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} |
2953 | |
2954 | static bool nodeHasBugReport(const ExplodedNode *N) { |
2955 | BugReporter &BR = static_cast<ExprEngine &>( |
2956 | N->getState()->getStateManager().getOwningEngine()).getBugReporter(); |
2957 | |
2958 | const auto EQClasses = |
2959 | llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end()); |
2960 | |
2961 | for (const auto &EQ : EQClasses) { |
2962 | for (const BugReport &Report : EQ) { |
2963 | if (Report.getErrorNode() == N) |
2964 | return true; |
2965 | } |
2966 | } |
2967 | return false; |
2968 | } |
2969 | |
2970 | |
2971 | |
2972 | |
2973 | |
2974 | static bool traverseHiddenNodes( |
2975 | const ExplodedNode *N, |
2976 | llvm::function_ref<void(const ExplodedNode *)> PreCallback, |
2977 | llvm::function_ref<void(const ExplodedNode *)> PostCallback, |
2978 | llvm::function_ref<bool(const ExplodedNode *)> Stop) { |
2979 | const ExplodedNode *FirstHiddenNode = N; |
2980 | while (FirstHiddenNode->pred_size() == 1 && |
2981 | isNodeHidden(*FirstHiddenNode->pred_begin())) { |
2982 | FirstHiddenNode = *FirstHiddenNode->pred_begin(); |
2983 | } |
2984 | const ExplodedNode *OtherNode = FirstHiddenNode; |
2985 | while (true) { |
2986 | PreCallback(OtherNode); |
2987 | if (Stop(OtherNode)) |
2988 | return true; |
2989 | |
2990 | if (OtherNode == N) |
2991 | break; |
2992 | PostCallback(OtherNode); |
2993 | |
2994 | OtherNode = *OtherNode->succ_begin(); |
2995 | } |
2996 | return false; |
2997 | } |
2998 | |
2999 | static std::string getNodeAttributes(const ExplodedNode *N, |
3000 | ExplodedGraph *) { |
3001 | SmallVector<StringRef, 10> Out; |
3002 | auto Noop = [](const ExplodedNode*){}; |
3003 | if (traverseHiddenNodes(N, Noop, Noop, &nodeHasBugReport)) { |
3004 | Out.push_back("style=filled"); |
3005 | Out.push_back("fillcolor=red"); |
3006 | } |
3007 | |
3008 | if (traverseHiddenNodes(N, Noop, Noop, |
3009 | [](const ExplodedNode *C) { return C->isSink(); })) |
3010 | Out.push_back("color=blue"); |
3011 | return llvm::join(Out, ","); |
3012 | } |
3013 | |
3014 | static bool isNodeHidden(const ExplodedNode *N) { |
3015 | return N->isTrivial(); |
3016 | } |
3017 | |
3018 | static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){ |
3019 | std::string sbuf; |
3020 | llvm::raw_string_ostream Out(sbuf); |
3021 | |
3022 | ProgramStateRef State = N->getState(); |
3023 | |
3024 | |
3025 | traverseHiddenNodes( |
3026 | N, |
3027 | [&](const ExplodedNode *OtherNode) { |
3028 | OtherNode->getLocation().print(, Out); |
3029 | if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag()) |
3030 | Out << "\\lTag:" << Tag->getTagDescription(); |
3031 | if (N->isSink()) |
3032 | Out << "\\lNode is sink\\l"; |
3033 | if (nodeHasBugReport(N)) |
3034 | Out << "\\lBug report attached\\l"; |
3035 | }, |
3036 | [&](const ExplodedNode *) { Out << "\\l--------\\l"; }, |
3037 | [&](const ExplodedNode *) { return false; }); |
3038 | |
3039 | Out << "\\l\\|"; |
3040 | |
3041 | Out << "StateID: ST" << State->getID() << ", NodeID: N" << N->getID(G) |
3042 | << " <" << (const void *)N << ">\\|"; |
3043 | |
3044 | bool SameAsAllPredecessors = |
3045 | std::all_of(N->pred_begin(), N->pred_end(), [&](const ExplodedNode *P) { |
3046 | return P->getState() == State; |
3047 | }); |
3048 | if (!SameAsAllPredecessors) |
3049 | State->printDOT(Out, N->getLocationContext()); |
3050 | return Out.str(); |
3051 | } |
3052 | }; |
3053 | |
3054 | } |
3055 | #endif |
3056 | |
3057 | void ExprEngine::ViewGraph(bool trim) { |
3058 | #ifndef NDEBUG |
3059 | std::string Filename = DumpGraph(trim); |
3060 | llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); |
3061 | #endif |
3062 | llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; |
3063 | } |
3064 | |
3065 | |
3066 | void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { |
3067 | #ifndef NDEBUG |
3068 | std::string Filename = DumpGraph(Nodes); |
3069 | llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); |
3070 | #endif |
3071 | llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; |
3072 | } |
3073 | |
3074 | std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { |
3075 | #ifndef NDEBUG |
3076 | if (trim) { |
3077 | std::vector<const ExplodedNode *> Src; |
3078 | |
3079 | |
3080 | for (BugReporter::EQClasses_iterator |
3081 | EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) { |
3082 | const auto *N = const_cast<ExplodedNode *>(EI->begin()->getErrorNode()); |
3083 | if (N) Src.push_back(N); |
3084 | } |
3085 | return DumpGraph(Src, Filename); |
3086 | } else { |
3087 | return llvm::WriteGraph(&G, "ExprEngine", , |
3088 | , Filename); |
3089 | } |
3090 | #endif |
3091 | llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; |
3092 | return ""; |
3093 | } |
3094 | |
3095 | std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode*> Nodes, |
3096 | StringRef Filename) { |
3097 | #ifndef NDEBUG |
3098 | std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); |
3099 | |
3100 | if (!TrimmedG.get()) { |
3101 | llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; |
3102 | } else { |
3103 | return llvm::WriteGraph(TrimmedG.get(), "TrimmedExprEngine", |
3104 | , |
3105 | , |
3106 | Filename); |
3107 | } |
3108 | #endif |
3109 | llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; |
3110 | return ""; |
3111 | } |
3112 | |
3113 | void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() { |
3114 | static int index = 0; |
3115 | return &index; |
3116 | } |
3117 | |