1 //===- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a meta-engine for path-sensitive dataflow analysis that
10 // is built on CoreEngine, but provides the boilerplate to execute transfer
11 // functions and build the ExplodedGraph at the expression level.
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/JsonSupport.h"
37 #include "clang/Basic/LLVM.h"
38 #include "clang/Basic/LangOptions.h"
39 #include "clang/Basic/PrettyStackTrace.h"
40 #include "clang/Basic/SourceLocation.h"
41 #include "clang/Basic/SourceManager.h"
42 #include "clang/Basic/Specifiers.h"
43 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
44 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
45 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
47 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
48 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49 #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
50 #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
51 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
52 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
53 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
54 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
55 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
56 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
58 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
59 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
60 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
61 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
62 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
63 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
64 #include "llvm/ADT/APSInt.h"
65 #include "llvm/ADT/DenseMap.h"
66 #include "llvm/ADT/ImmutableMap.h"
67 #include "llvm/ADT/ImmutableSet.h"
68 #include "llvm/ADT/SmallVector.h"
69 #include "llvm/ADT/Statistic.h"
70 #include "llvm/Support/Casting.h"
71 #include "llvm/Support/Compiler.h"
72 #include "llvm/Support/DOTGraphTraits.h"
73 #include "llvm/Support/ErrorHandling.h"
74 #include "llvm/Support/GraphWriter.h"
75 #include "llvm/Support/SaveAndRestore.h"
76 #include "llvm/Support/raw_ostream.h"
77 #include <cassert>
78 #include <cstdint>
79 #include <memory>
80 #include <optional>
81 #include <string>
82 #include <tuple>
83 #include <utility>
84 #include <vector>
85
86 using namespace clang;
87 using namespace ento;
88
89 #define DEBUG_TYPE "ExprEngine"
90
91 STATISTIC(NumRemoveDeadBindings,
92 "The # of times RemoveDeadBindings is called");
93 STATISTIC(NumMaxBlockCountReached,
94 "The # of aborted paths due to reaching the maximum block count in "
95 "a top level function");
96 STATISTIC(NumMaxBlockCountReachedInInlined,
97 "The # of aborted paths due to reaching the maximum block count in "
98 "an inlined function");
99 STATISTIC(NumTimesRetriedWithoutInlining,
100 "The # of times we re-evaluated a call without inlining");
101
102 //===----------------------------------------------------------------------===//
103 // Internal program state traits.
104 //===----------------------------------------------------------------------===//
105
106 namespace {
107
108 // When modeling a C++ constructor, for a variety of reasons we need to track
109 // the location of the object for the duration of its ConstructionContext.
110 // ObjectsUnderConstruction maps statements within the construction context
111 // to the object's location, so that on every such statement the location
112 // could have been retrieved.
113
114 /// ConstructedObjectKey is used for being able to find the path-sensitive
115 /// memory region of a freshly constructed object while modeling the AST node
116 /// that syntactically represents the object that is being constructed.
117 /// Semantics of such nodes may sometimes require access to the region that's
118 /// not otherwise present in the program state, or to the very fact that
119 /// the construction context was present and contained references to these
120 /// AST nodes.
121 class ConstructedObjectKey {
122 using ConstructedObjectKeyImpl =
123 std::pair<ConstructionContextItem, const LocationContext *>;
124 const ConstructedObjectKeyImpl Impl;
125
126 public:
ConstructedObjectKey(const ConstructionContextItem & Item,const LocationContext * LC)127 explicit ConstructedObjectKey(const ConstructionContextItem &Item,
128 const LocationContext *LC)
129 : Impl(Item, LC) {}
130
getItem() const131 const ConstructionContextItem &getItem() const { return Impl.first; }
getLocationContext() const132 const LocationContext *getLocationContext() const { return Impl.second; }
133
getASTContext() const134 ASTContext &getASTContext() const {
135 return getLocationContext()->getDecl()->getASTContext();
136 }
137
printJson(llvm::raw_ostream & Out,PrinterHelper * Helper,PrintingPolicy & PP) const138 void printJson(llvm::raw_ostream &Out, PrinterHelper *Helper,
139 PrintingPolicy &PP) const {
140 const Stmt *S = getItem().getStmtOrNull();
141 const CXXCtorInitializer *I = nullptr;
142 if (!S)
143 I = getItem().getCXXCtorInitializer();
144
145 if (S)
146 Out << "\"stmt_id\": " << S->getID(getASTContext());
147 else
148 Out << "\"init_id\": " << I->getID(getASTContext());
149
150 // Kind
151 Out << ", \"kind\": \"" << getItem().getKindAsString()
152 << "\", \"argument_index\": ";
153
154 if (getItem().getKind() == ConstructionContextItem::ArgumentKind)
155 Out << getItem().getIndex();
156 else
157 Out << "null";
158
159 // Pretty-print
160 Out << ", \"pretty\": ";
161
162 if (S) {
163 S->printJson(Out, Helper, PP, /*AddQuotes=*/true);
164 } else {
165 Out << '\"' << I->getAnyMember()->getDeclName() << '\"';
166 }
167 }
168
Profile(llvm::FoldingSetNodeID & ID) const169 void Profile(llvm::FoldingSetNodeID &ID) const {
170 ID.Add(Impl.first);
171 ID.AddPointer(Impl.second);
172 }
173
operator ==(const ConstructedObjectKey & RHS) const174 bool operator==(const ConstructedObjectKey &RHS) const {
175 return Impl == RHS.Impl;
176 }
177
operator <(const ConstructedObjectKey & RHS) const178 bool operator<(const ConstructedObjectKey &RHS) const {
179 return Impl < RHS.Impl;
180 }
181 };
182 } // namespace
183
184 typedef llvm::ImmutableMap<ConstructedObjectKey, SVal>
185 ObjectsUnderConstructionMap;
186 REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
187 ObjectsUnderConstructionMap)
188
189 // This trait is responsible for storing the index of the element that is to be
190 // constructed in the next iteration. As a result a CXXConstructExpr is only
191 // stored if it is array type. Also the index is the index of the continuous
192 // memory region, which is important for multi-dimensional arrays. E.g:: int
193 // arr[2][2]; assume arr[1][1] will be the next element under construction, so
194 // the index is 3.
195 typedef llvm::ImmutableMap<
196 std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
197 IndexOfElementToConstructMap;
198 REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
199 IndexOfElementToConstructMap)
200
201 // This trait is responsible for holding our pending ArrayInitLoopExprs.
202 // It pairs the LocationContext and the initializer CXXConstructExpr with
203 // the size of the array that's being copy initialized.
204 typedef llvm::ImmutableMap<
205 std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
206 PendingInitLoopMap;
207 REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
208
209 typedef llvm::ImmutableMap<const LocationContext *, unsigned>
210 PendingArrayDestructionMap;
211 REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingArrayDestruction,
212 PendingArrayDestructionMap)
213
214 //===----------------------------------------------------------------------===//
215 // Engine construction and deletion.
216 //===----------------------------------------------------------------------===//
217
218 static const char* TagProviderName = "ExprEngine";
219
ExprEngine(cross_tu::CrossTranslationUnitContext & CTU,AnalysisManager & mgr,SetOfConstDecls * VisitedCalleesIn,FunctionSummariesTy * FS,InliningModes HowToInlineIn)220 ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
221 AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
222 FunctionSummariesTy *FS, InliningModes HowToInlineIn)
223 : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled),
224 AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
225 Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
226 StateMgr(getContext(), mgr.getStoreManagerCreator(),
227 mgr.getConstraintManagerCreator(), G.getAllocator(), this),
228 SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
229 svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
230 BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
231 HowToInline(HowToInlineIn) {
232 unsigned TrimInterval = mgr.options.GraphTrimInterval;
233 if (TrimInterval != 0) {
234 // Enable eager node reclamation when constructing the ExplodedGraph.
235 G.enableNodeReclamation(TrimInterval);
236 }
237 }
238
239 //===----------------------------------------------------------------------===//
240 // Utility methods.
241 //===----------------------------------------------------------------------===//
242
getInitialState(const LocationContext * InitLoc)243 ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
244 ProgramStateRef state = StateMgr.getInitialState(InitLoc);
245 const Decl *D = InitLoc->getDecl();
246
247 // Preconditions.
248 // FIXME: It would be nice if we had a more general mechanism to add
249 // such preconditions. Some day.
250 do {
251 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
252 // Precondition: the first argument of 'main' is an integer guaranteed
253 // to be > 0.
254 const IdentifierInfo *II = FD->getIdentifier();
255 if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
256 break;
257
258 const ParmVarDecl *PD = FD->getParamDecl(0);
259 QualType T = PD->getType();
260 const auto *BT = dyn_cast<BuiltinType>(T);
261 if (!BT || !BT->isInteger())
262 break;
263
264 const MemRegion *R = state->getRegion(PD, InitLoc);
265 if (!R)
266 break;
267
268 SVal V = state->getSVal(loc::MemRegionVal(R));
269 SVal Constraint_untested = evalBinOp(state, BO_GT, V,
270 svalBuilder.makeZeroVal(T),
271 svalBuilder.getConditionType());
272
273 std::optional<DefinedOrUnknownSVal> Constraint =
274 Constraint_untested.getAs<DefinedOrUnknownSVal>();
275
276 if (!Constraint)
277 break;
278
279 if (ProgramStateRef newState = state->assume(*Constraint, true))
280 state = newState;
281 }
282 break;
283 }
284 while (false);
285
286 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
287 // Precondition: 'self' is always non-null upon entry to an Objective-C
288 // method.
289 const ImplicitParamDecl *SelfD = MD->getSelfDecl();
290 const MemRegion *R = state->getRegion(SelfD, InitLoc);
291 SVal V = state->getSVal(loc::MemRegionVal(R));
292
293 if (std::optional<Loc> LV = V.getAs<Loc>()) {
294 // Assume that the pointer value in 'self' is non-null.
295 state = state->assume(*LV, true);
296 assert(state && "'self' cannot be null");
297 }
298 }
299
300 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
301 if (!MD->isStatic()) {
302 // Precondition: 'this' is always non-null upon entry to the
303 // top-level function. This is our starting assumption for
304 // analyzing an "open" program.
305 const StackFrameContext *SFC = InitLoc->getStackFrame();
306 if (SFC->getParent() == nullptr) {
307 loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
308 SVal V = state->getSVal(L);
309 if (std::optional<Loc> LV = V.getAs<Loc>()) {
310 state = state->assume(*LV, true);
311 assert(state && "'this' cannot be null");
312 }
313 }
314 }
315 }
316
317 return state;
318 }
319
createTemporaryRegionIfNeeded(ProgramStateRef State,const LocationContext * LC,const Expr * InitWithAdjustments,const Expr * Result,const SubRegion ** OutRegionWithAdjustments)320 ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
321 ProgramStateRef State, const LocationContext *LC,
322 const Expr *InitWithAdjustments, const Expr *Result,
323 const SubRegion **OutRegionWithAdjustments) {
324 // FIXME: This function is a hack that works around the quirky AST
325 // we're often having with respect to C++ temporaries. If only we modelled
326 // the actual execution order of statements properly in the CFG,
327 // all the hassle with adjustments would not be necessary,
328 // and perhaps the whole function would be removed.
329 SVal InitValWithAdjustments = State->getSVal(InitWithAdjustments, LC);
330 if (!Result) {
331 // If we don't have an explicit result expression, we're in "if needed"
332 // mode. Only create a region if the current value is a NonLoc.
333 if (!isa<NonLoc>(InitValWithAdjustments)) {
334 if (OutRegionWithAdjustments)
335 *OutRegionWithAdjustments = nullptr;
336 return State;
337 }
338 Result = InitWithAdjustments;
339 } else {
340 // We need to create a region no matter what. Make sure we don't try to
341 // stuff a Loc into a non-pointer temporary region.
342 assert(!isa<Loc>(InitValWithAdjustments) ||
343 Loc::isLocType(Result->getType()) ||
344 Result->getType()->isMemberPointerType());
345 }
346
347 ProgramStateManager &StateMgr = State->getStateManager();
348 MemRegionManager &MRMgr = StateMgr.getRegionManager();
349 StoreManager &StoreMgr = StateMgr.getStoreManager();
350
351 // MaterializeTemporaryExpr may appear out of place, after a few field and
352 // base-class accesses have been made to the object, even though semantically
353 // it is the whole object that gets materialized and lifetime-extended.
354 //
355 // For example:
356 //
357 // `-MaterializeTemporaryExpr
358 // `-MemberExpr
359 // `-CXXTemporaryObjectExpr
360 //
361 // instead of the more natural
362 //
363 // `-MemberExpr
364 // `-MaterializeTemporaryExpr
365 // `-CXXTemporaryObjectExpr
366 //
367 // Use the usual methods for obtaining the expression of the base object,
368 // and record the adjustments that we need to make to obtain the sub-object
369 // that the whole expression 'Ex' refers to. This trick is usual,
370 // in the sense that CodeGen takes a similar route.
371
372 SmallVector<const Expr *, 2> CommaLHSs;
373 SmallVector<SubobjectAdjustment, 2> Adjustments;
374
375 const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments(
376 CommaLHSs, Adjustments);
377
378 // Take the region for Init, i.e. for the whole object. If we do not remember
379 // the region in which the object originally was constructed, come up with
380 // a new temporary region out of thin air and copy the contents of the object
381 // (which are currently present in the Environment, because Init is an rvalue)
382 // into that region. This is not correct, but it is better than nothing.
383 const TypedValueRegion *TR = nullptr;
384 if (const auto *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) {
385 if (std::optional<SVal> V = getObjectUnderConstruction(State, MT, LC)) {
386 State = finishObjectConstruction(State, MT, LC);
387 State = State->BindExpr(Result, LC, *V);
388 return State;
389 } else {
390 StorageDuration SD = MT->getStorageDuration();
391 // If this object is bound to a reference with static storage duration, we
392 // put it in a different region to prevent "address leakage" warnings.
393 if (SD == SD_Static || SD == SD_Thread) {
394 TR = MRMgr.getCXXStaticTempObjectRegion(Init);
395 } else {
396 TR = MRMgr.getCXXTempObjectRegion(Init, LC);
397 }
398 }
399 } else {
400 TR = MRMgr.getCXXTempObjectRegion(Init, LC);
401 }
402
403 SVal Reg = loc::MemRegionVal(TR);
404 SVal BaseReg = Reg;
405
406 // Make the necessary adjustments to obtain the sub-object.
407 for (const SubobjectAdjustment &Adj : llvm::reverse(Adjustments)) {
408 switch (Adj.Kind) {
409 case SubobjectAdjustment::DerivedToBaseAdjustment:
410 Reg = StoreMgr.evalDerivedToBase(Reg, Adj.DerivedToBase.BasePath);
411 break;
412 case SubobjectAdjustment::FieldAdjustment:
413 Reg = StoreMgr.getLValueField(Adj.Field, Reg);
414 break;
415 case SubobjectAdjustment::MemberPointerAdjustment:
416 // FIXME: Unimplemented.
417 State = State->invalidateRegions(Reg, InitWithAdjustments,
418 currBldrCtx->blockCount(), LC, true,
419 nullptr, nullptr, nullptr);
420 return State;
421 }
422 }
423
424 // What remains is to copy the value of the object to the new region.
425 // FIXME: In other words, what we should always do is copy value of the
426 // Init expression (which corresponds to the bigger object) to the whole
427 // temporary region TR. However, this value is often no longer present
428 // in the Environment. If it has disappeared, we instead invalidate TR.
429 // Still, what we can do is assign the value of expression Ex (which
430 // corresponds to the sub-object) to the TR's sub-region Reg. At least,
431 // values inside Reg would be correct.
432 SVal InitVal = State->getSVal(Init, LC);
433 if (InitVal.isUnknown()) {
434 InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(),
435 currBldrCtx->blockCount());
436 State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
437
438 // Then we'd need to take the value that certainly exists and bind it
439 // over.
440 if (InitValWithAdjustments.isUnknown()) {
441 // Try to recover some path sensitivity in case we couldn't
442 // compute the value.
443 InitValWithAdjustments = getSValBuilder().conjureSymbolVal(
444 Result, LC, InitWithAdjustments->getType(),
445 currBldrCtx->blockCount());
446 }
447 State =
448 State->bindLoc(Reg.castAs<Loc>(), InitValWithAdjustments, LC, false);
449 } else {
450 State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
451 }
452
453 // The result expression would now point to the correct sub-region of the
454 // newly created temporary region. Do this last in order to getSVal of Init
455 // correctly in case (Result == Init).
456 if (Result->isGLValue()) {
457 State = State->BindExpr(Result, LC, Reg);
458 } else {
459 State = State->BindExpr(Result, LC, InitValWithAdjustments);
460 }
461
462 // Notify checkers once for two bindLoc()s.
463 State = processRegionChange(State, TR, LC);
464
465 if (OutRegionWithAdjustments)
466 *OutRegionWithAdjustments = cast<SubRegion>(Reg.getAsRegion());
467 return State;
468 }
469
setIndexOfElementToConstruct(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx,unsigned Idx)470 ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
471 ProgramStateRef State, const CXXConstructExpr *E,
472 const LocationContext *LCtx, unsigned Idx) {
473 auto Key = std::make_pair(E, LCtx->getStackFrame());
474
475 assert(!State->contains<IndexOfElementToConstruct>(Key) || Idx > 0);
476
477 return State->set<IndexOfElementToConstruct>(Key, Idx);
478 }
479
480 std::optional<unsigned>
getPendingInitLoop(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx)481 ExprEngine::getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E,
482 const LocationContext *LCtx) {
483 const unsigned *V = State->get<PendingInitLoop>({E, LCtx->getStackFrame()});
484 return V ? std::make_optional(*V) : std::nullopt;
485 }
486
removePendingInitLoop(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx)487 ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
488 const CXXConstructExpr *E,
489 const LocationContext *LCtx) {
490 auto Key = std::make_pair(E, LCtx->getStackFrame());
491
492 assert(E && State->contains<PendingInitLoop>(Key));
493 return State->remove<PendingInitLoop>(Key);
494 }
495
setPendingInitLoop(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx,unsigned Size)496 ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
497 const CXXConstructExpr *E,
498 const LocationContext *LCtx,
499 unsigned Size) {
500 auto Key = std::make_pair(E, LCtx->getStackFrame());
501
502 assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
503
504 return State->set<PendingInitLoop>(Key, Size);
505 }
506
507 std::optional<unsigned>
getIndexOfElementToConstruct(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx)508 ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
509 const CXXConstructExpr *E,
510 const LocationContext *LCtx) {
511 const unsigned *V =
512 State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()});
513 return V ? std::make_optional(*V) : std::nullopt;
514 }
515
516 ProgramStateRef
removeIndexOfElementToConstruct(ProgramStateRef State,const CXXConstructExpr * E,const LocationContext * LCtx)517 ExprEngine::removeIndexOfElementToConstruct(ProgramStateRef State,
518 const CXXConstructExpr *E,
519 const LocationContext *LCtx) {
520 auto Key = std::make_pair(E, LCtx->getStackFrame());
521
522 assert(E && State->contains<IndexOfElementToConstruct>(Key));
523 return State->remove<IndexOfElementToConstruct>(Key);
524 }
525
526 std::optional<unsigned>
getPendingArrayDestruction(ProgramStateRef State,const LocationContext * LCtx)527 ExprEngine::getPendingArrayDestruction(ProgramStateRef State,
528 const LocationContext *LCtx) {
529 assert(LCtx && "LocationContext shouldn't be null!");
530
531 const unsigned *V =
532 State->get<PendingArrayDestruction>(LCtx->getStackFrame());
533 return V ? std::make_optional(*V) : std::nullopt;
534 }
535
setPendingArrayDestruction(ProgramStateRef State,const LocationContext * LCtx,unsigned Idx)536 ProgramStateRef ExprEngine::setPendingArrayDestruction(
537 ProgramStateRef State, const LocationContext *LCtx, unsigned Idx) {
538 assert(LCtx && "LocationContext shouldn't be null!");
539
540 auto Key = LCtx->getStackFrame();
541
542 return State->set<PendingArrayDestruction>(Key, Idx);
543 }
544
545 ProgramStateRef
removePendingArrayDestruction(ProgramStateRef State,const LocationContext * LCtx)546 ExprEngine::removePendingArrayDestruction(ProgramStateRef State,
547 const LocationContext *LCtx) {
548 assert(LCtx && "LocationContext shouldn't be null!");
549
550 auto Key = LCtx->getStackFrame();
551
552 assert(LCtx && State->contains<PendingArrayDestruction>(Key));
553 return State->remove<PendingArrayDestruction>(Key);
554 }
555
556 ProgramStateRef
addObjectUnderConstruction(ProgramStateRef State,const ConstructionContextItem & Item,const LocationContext * LC,SVal V)557 ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
558 const ConstructionContextItem &Item,
559 const LocationContext *LC, SVal V) {
560 ConstructedObjectKey Key(Item, LC->getStackFrame());
561
562 const Expr *Init = nullptr;
563
564 if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) {
565 if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl()))
566 Init = VD->getInit();
567 }
568
569 if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull()))
570 Init = *(LE->capture_init_begin() + Item.getIndex());
571
572 if (!Init && !Item.getStmtOrNull())
573 Init = Item.getCXXCtorInitializer()->getInit();
574
575 // In an ArrayInitLoopExpr the real initializer is returned by
576 // getSubExpr(). Note that AILEs can be nested in case of
577 // multidimesnional arrays.
578 if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
579 Init = extractElementInitializerFromNestedAILE(AILE);
580
581 // FIXME: Currently the state might already contain the marker due to
582 // incorrect handling of temporaries bound to default parameters.
583 // The state will already contain the marker if we construct elements
584 // in an array, as we visit the same statement multiple times before
585 // the array declaration. The marker is removed when we exit the
586 // constructor call.
587 assert((!State->get<ObjectsUnderConstruction>(Key) ||
588 Key.getItem().getKind() ==
589 ConstructionContextItem::TemporaryDestructorKind ||
590 State->contains<IndexOfElementToConstruct>(
591 {dyn_cast_or_null<CXXConstructExpr>(Init), LC})) &&
592 "The object is already marked as `UnderConstruction`, when it's not "
593 "supposed to!");
594 return State->set<ObjectsUnderConstruction>(Key, V);
595 }
596
597 std::optional<SVal>
getObjectUnderConstruction(ProgramStateRef State,const ConstructionContextItem & Item,const LocationContext * LC)598 ExprEngine::getObjectUnderConstruction(ProgramStateRef State,
599 const ConstructionContextItem &Item,
600 const LocationContext *LC) {
601 ConstructedObjectKey Key(Item, LC->getStackFrame());
602 const SVal *V = State->get<ObjectsUnderConstruction>(Key);
603 return V ? std::make_optional(*V) : std::nullopt;
604 }
605
606 ProgramStateRef
finishObjectConstruction(ProgramStateRef State,const ConstructionContextItem & Item,const LocationContext * LC)607 ExprEngine::finishObjectConstruction(ProgramStateRef State,
608 const ConstructionContextItem &Item,
609 const LocationContext *LC) {
610 ConstructedObjectKey Key(Item, LC->getStackFrame());
611 assert(State->contains<ObjectsUnderConstruction>(Key));
612 return State->remove<ObjectsUnderConstruction>(Key);
613 }
614
elideDestructor(ProgramStateRef State,const CXXBindTemporaryExpr * BTE,const LocationContext * LC)615 ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State,
616 const CXXBindTemporaryExpr *BTE,
617 const LocationContext *LC) {
618 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
619 // FIXME: Currently the state might already contain the marker due to
620 // incorrect handling of temporaries bound to default parameters.
621 return State->set<ObjectsUnderConstruction>(Key, UnknownVal());
622 }
623
624 ProgramStateRef
cleanupElidedDestructor(ProgramStateRef State,const CXXBindTemporaryExpr * BTE,const LocationContext * LC)625 ExprEngine::cleanupElidedDestructor(ProgramStateRef State,
626 const CXXBindTemporaryExpr *BTE,
627 const LocationContext *LC) {
628 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
629 assert(State->contains<ObjectsUnderConstruction>(Key));
630 return State->remove<ObjectsUnderConstruction>(Key);
631 }
632
isDestructorElided(ProgramStateRef State,const CXXBindTemporaryExpr * BTE,const LocationContext * LC)633 bool ExprEngine::isDestructorElided(ProgramStateRef State,
634 const CXXBindTemporaryExpr *BTE,
635 const LocationContext *LC) {
636 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
637 return State->contains<ObjectsUnderConstruction>(Key);
638 }
639
areAllObjectsFullyConstructed(ProgramStateRef State,const LocationContext * FromLC,const LocationContext * ToLC)640 bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State,
641 const LocationContext *FromLC,
642 const LocationContext *ToLC) {
643 const LocationContext *LC = FromLC;
644 while (LC != ToLC) {
645 assert(LC && "ToLC must be a parent of FromLC!");
646 for (auto I : State->get<ObjectsUnderConstruction>())
647 if (I.first.getLocationContext() == LC)
648 return false;
649
650 LC = LC->getParent();
651 }
652 return true;
653 }
654
655
656 //===----------------------------------------------------------------------===//
657 // Top-level transfer function logic (Dispatcher).
658 //===----------------------------------------------------------------------===//
659
660 /// evalAssume - Called by ConstraintManager. Used to call checker-specific
661 /// logic for handling assumptions on symbolic values.
processAssume(ProgramStateRef state,SVal cond,bool assumption)662 ProgramStateRef ExprEngine::processAssume(ProgramStateRef state,
663 SVal cond, bool assumption) {
664 return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
665 }
666
667 ProgramStateRef
processRegionChanges(ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > Explicits,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call)668 ExprEngine::processRegionChanges(ProgramStateRef state,
669 const InvalidatedSymbols *invalidated,
670 ArrayRef<const MemRegion *> Explicits,
671 ArrayRef<const MemRegion *> Regions,
672 const LocationContext *LCtx,
673 const CallEvent *Call) {
674 return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
675 Explicits, Regions,
676 LCtx, Call);
677 }
678
679 static void
printObjectsUnderConstructionJson(raw_ostream & Out,ProgramStateRef State,const char * NL,const LocationContext * LCtx,unsigned int Space=0,bool IsDot=false)680 printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
681 const char *NL, const LocationContext *LCtx,
682 unsigned int Space = 0, bool IsDot = false) {
683 PrintingPolicy PP =
684 LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
685
686 ++Space;
687 bool HasItem = false;
688
689 // Store the last key.
690 const ConstructedObjectKey *LastKey = nullptr;
691 for (const auto &I : State->get<ObjectsUnderConstruction>()) {
692 const ConstructedObjectKey &Key = I.first;
693 if (Key.getLocationContext() != LCtx)
694 continue;
695
696 if (!HasItem) {
697 Out << '[' << NL;
698 HasItem = true;
699 }
700
701 LastKey = &Key;
702 }
703
704 for (const auto &I : State->get<ObjectsUnderConstruction>()) {
705 const ConstructedObjectKey &Key = I.first;
706 SVal Value = I.second;
707 if (Key.getLocationContext() != LCtx)
708 continue;
709
710 Indent(Out, Space, IsDot) << "{ ";
711 Key.printJson(Out, nullptr, PP);
712 Out << ", \"value\": \"" << Value << "\" }";
713
714 if (&Key != LastKey)
715 Out << ',';
716 Out << NL;
717 }
718
719 if (HasItem)
720 Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
721 else {
722 Out << "null ";
723 }
724 }
725
printIndicesOfElementsToConstructJson(raw_ostream & Out,ProgramStateRef State,const char * NL,const LocationContext * LCtx,unsigned int Space=0,bool IsDot=false)726 static void printIndicesOfElementsToConstructJson(
727 raw_ostream &Out, ProgramStateRef State, const char *NL,
728 const LocationContext *LCtx, unsigned int Space = 0, bool IsDot = false) {
729 using KeyT = std::pair<const Expr *, const LocationContext *>;
730
731 const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
732 PrintingPolicy PP = Context.getPrintingPolicy();
733
734 ++Space;
735 bool HasItem = false;
736
737 // Store the last key.
738 KeyT LastKey;
739 for (const auto &I : State->get<IndexOfElementToConstruct>()) {
740 const KeyT &Key = I.first;
741 if (Key.second != LCtx)
742 continue;
743
744 if (!HasItem) {
745 Out << '[' << NL;
746 HasItem = true;
747 }
748
749 LastKey = Key;
750 }
751
752 for (const auto &I : State->get<IndexOfElementToConstruct>()) {
753 const KeyT &Key = I.first;
754 unsigned Value = I.second;
755 if (Key.second != LCtx)
756 continue;
757
758 Indent(Out, Space, IsDot) << "{ ";
759
760 // Expr
761 const Expr *E = Key.first;
762 Out << "\"stmt_id\": " << E->getID(Context);
763
764 // Kind
765 Out << ", \"kind\": null";
766
767 // Pretty-print
768 Out << ", \"pretty\": ";
769 Out << "\"" << E->getStmtClassName() << ' '
770 << E->getSourceRange().printToString(Context.getSourceManager()) << " '"
771 << QualType::getAsString(E->getType().split(), PP);
772 Out << "'\"";
773
774 Out << ", \"value\": \"Current index: " << Value - 1 << "\" }";
775
776 if (Key != LastKey)
777 Out << ',';
778 Out << NL;
779 }
780
781 if (HasItem)
782 Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
783 else {
784 Out << "null ";
785 }
786 }
787
printPendingInitLoopJson(raw_ostream & Out,ProgramStateRef State,const char * NL,const LocationContext * LCtx,unsigned int Space=0,bool IsDot=false)788 static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State,
789 const char *NL,
790 const LocationContext *LCtx,
791 unsigned int Space = 0,
792 bool IsDot = false) {
793 using KeyT = std::pair<const CXXConstructExpr *, const LocationContext *>;
794
795 const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
796 PrintingPolicy PP = Context.getPrintingPolicy();
797
798 ++Space;
799 bool HasItem = false;
800
801 // Store the last key.
802 KeyT LastKey;
803 for (const auto &I : State->get<PendingInitLoop>()) {
804 const KeyT &Key = I.first;
805 if (Key.second != LCtx)
806 continue;
807
808 if (!HasItem) {
809 Out << '[' << NL;
810 HasItem = true;
811 }
812
813 LastKey = Key;
814 }
815
816 for (const auto &I : State->get<PendingInitLoop>()) {
817 const KeyT &Key = I.first;
818 unsigned Value = I.second;
819 if (Key.second != LCtx)
820 continue;
821
822 Indent(Out, Space, IsDot) << "{ ";
823
824 const CXXConstructExpr *E = Key.first;
825 Out << "\"stmt_id\": " << E->getID(Context);
826
827 Out << ", \"kind\": null";
828 Out << ", \"pretty\": ";
829 Out << '\"' << E->getStmtClassName() << ' '
830 << E->getSourceRange().printToString(Context.getSourceManager()) << " '"
831 << QualType::getAsString(E->getType().split(), PP);
832 Out << "'\"";
833
834 Out << ", \"value\": \"Flattened size: " << Value << "\"}";
835
836 if (Key != LastKey)
837 Out << ',';
838 Out << NL;
839 }
840
841 if (HasItem)
842 Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
843 else {
844 Out << "null ";
845 }
846 }
847
848 static void
printPendingArrayDestructionsJson(raw_ostream & Out,ProgramStateRef State,const char * NL,const LocationContext * LCtx,unsigned int Space=0,bool IsDot=false)849 printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State,
850 const char *NL, const LocationContext *LCtx,
851 unsigned int Space = 0, bool IsDot = false) {
852 using KeyT = const LocationContext *;
853
854 ++Space;
855 bool HasItem = false;
856
857 // Store the last key.
858 KeyT LastKey = nullptr;
859 for (const auto &I : State->get<PendingArrayDestruction>()) {
860 const KeyT &Key = I.first;
861 if (Key != LCtx)
862 continue;
863
864 if (!HasItem) {
865 Out << '[' << NL;
866 HasItem = true;
867 }
868
869 LastKey = Key;
870 }
871
872 for (const auto &I : State->get<PendingArrayDestruction>()) {
873 const KeyT &Key = I.first;
874 if (Key != LCtx)
875 continue;
876
877 Indent(Out, Space, IsDot) << "{ ";
878
879 Out << "\"stmt_id\": null";
880 Out << ", \"kind\": null";
881 Out << ", \"pretty\": \"Current index: \"";
882 Out << ", \"value\": \"" << I.second << "\" }";
883
884 if (Key != LastKey)
885 Out << ',';
886 Out << NL;
887 }
888
889 if (HasItem)
890 Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
891 else {
892 Out << "null ";
893 }
894 }
895
896 /// A helper function to generalize program state trait printing.
897 /// The function invokes Printer as 'Printer(Out, State, NL, LC, Space, IsDot,
898 /// std::forward<Args>(args)...)'. \n One possible type for Printer is
899 /// 'void()(raw_ostream &, ProgramStateRef, const char *, const LocationContext
900 /// *, unsigned int, bool, ...)' \n \param Trait The state trait to be printed.
901 /// \param Printer A void function that prints Trait.
902 /// \param Args An additional parameter pack that is passed to Print upon
903 /// invocation.
904 template <typename Trait, typename Printer, typename... Args>
printStateTraitWithLocationContextJson(raw_ostream & Out,ProgramStateRef State,const LocationContext * LCtx,const char * NL,unsigned int Space,bool IsDot,const char * jsonPropertyName,Printer printer,Args &&...args)905 static void printStateTraitWithLocationContextJson(
906 raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx,
907 const char *NL, unsigned int Space, bool IsDot,
908 const char *jsonPropertyName, Printer printer, Args &&...args) {
909
910 using RequiredType =
911 void (*)(raw_ostream &, ProgramStateRef, const char *,
912 const LocationContext *, unsigned int, bool, Args &&...);
913
914 // Try to do as much compile time checking as possible.
915 // FIXME: check for invocable instead of function?
916 static_assert(std::is_function_v<std::remove_pointer_t<Printer>>,
917 "Printer is not a function!");
918 static_assert(std::is_convertible_v<Printer, RequiredType>,
919 "Printer doesn't have the required type!");
920
921 if (LCtx && !State->get<Trait>().isEmpty()) {
922 Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": ";
923 ++Space;
924 Out << '[' << NL;
925 LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
926 printer(Out, State, NL, LC, Space, IsDot, std::forward<Args>(args)...);
927 });
928
929 --Space;
930 Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName".
931 }
932 }
933
printJson(raw_ostream & Out,ProgramStateRef State,const LocationContext * LCtx,const char * NL,unsigned int Space,bool IsDot) const934 void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
935 const LocationContext *LCtx, const char *NL,
936 unsigned int Space, bool IsDot) const {
937
938 printStateTraitWithLocationContextJson<ObjectsUnderConstruction>(
939 Out, State, LCtx, NL, Space, IsDot, "constructing_objects",
940 printObjectsUnderConstructionJson);
941 printStateTraitWithLocationContextJson<IndexOfElementToConstruct>(
942 Out, State, LCtx, NL, Space, IsDot, "index_of_element",
943 printIndicesOfElementsToConstructJson);
944 printStateTraitWithLocationContextJson<PendingInitLoop>(
945 Out, State, LCtx, NL, Space, IsDot, "pending_init_loops",
946 printPendingInitLoopJson);
947 printStateTraitWithLocationContextJson<PendingArrayDestruction>(
948 Out, State, LCtx, NL, Space, IsDot, "pending_destructors",
949 printPendingArrayDestructionsJson);
950
951 getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space,
952 IsDot);
953 }
954
processEndWorklist()955 void ExprEngine::processEndWorklist() {
956 // This prints the name of the top-level function if we crash.
957 PrettyStackTraceLocationContext CrashInfo(getRootLocationContext());
958 getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
959 }
960
processCFGElement(const CFGElement E,ExplodedNode * Pred,unsigned StmtIdx,NodeBuilderContext * Ctx)961 void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
962 unsigned StmtIdx, NodeBuilderContext *Ctx) {
963 PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
964 currStmtIdx = StmtIdx;
965 currBldrCtx = Ctx;
966
967 switch (E.getKind()) {
968 case CFGElement::Statement:
969 case CFGElement::Constructor:
970 case CFGElement::CXXRecordTypedCall:
971 ProcessStmt(E.castAs<CFGStmt>().getStmt(), Pred);
972 return;
973 case CFGElement::Initializer:
974 ProcessInitializer(E.castAs<CFGInitializer>(), Pred);
975 return;
976 case CFGElement::NewAllocator:
977 ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(),
978 Pred);
979 return;
980 case CFGElement::AutomaticObjectDtor:
981 case CFGElement::DeleteDtor:
982 case CFGElement::BaseDtor:
983 case CFGElement::MemberDtor:
984 case CFGElement::TemporaryDtor:
985 ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
986 return;
987 case CFGElement::LoopExit:
988 ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
989 return;
990 case CFGElement::LifetimeEnds:
991 case CFGElement::ScopeBegin:
992 case CFGElement::ScopeEnd:
993 return;
994 }
995 }
996
shouldRemoveDeadBindings(AnalysisManager & AMgr,const Stmt * S,const ExplodedNode * Pred,const LocationContext * LC)997 static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
998 const Stmt *S,
999 const ExplodedNode *Pred,
1000 const LocationContext *LC) {
1001 // Are we never purging state values?
1002 if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
1003 return false;
1004
1005 // Is this the beginning of a basic block?
1006 if (Pred->getLocation().getAs<BlockEntrance>())
1007 return true;
1008
1009 // Is this on a non-expression?
1010 if (!isa<Expr>(S))
1011 return true;
1012
1013 // Run before processing a call.
1014 if (CallEvent::isCallStmt(S))
1015 return true;
1016
1017 // Is this an expression that is consumed by another expression? If so,
1018 // postpone cleaning out the state.
1019 ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap();
1020 return !PM.isConsumedExpr(cast<Expr>(S));
1021 }
1022
removeDead(ExplodedNode * Pred,ExplodedNodeSet & Out,const Stmt * ReferenceStmt,const LocationContext * LC,const Stmt * DiagnosticStmt,ProgramPoint::Kind K)1023 void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
1024 const Stmt *ReferenceStmt,
1025 const LocationContext *LC,
1026 const Stmt *DiagnosticStmt,
1027 ProgramPoint::Kind K) {
1028 assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
1029 ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt))
1030 && "PostStmt is not generally supported by the SymbolReaper yet");
1031 assert(LC && "Must pass the current (or expiring) LocationContext");
1032
1033 if (!DiagnosticStmt) {
1034 DiagnosticStmt = ReferenceStmt;
1035 assert(DiagnosticStmt && "Required for clearing a LocationContext");
1036 }
1037
1038 NumRemoveDeadBindings++;
1039 ProgramStateRef CleanedState = Pred->getState();
1040
1041 // LC is the location context being destroyed, but SymbolReaper wants a
1042 // location context that is still live. (If this is the top-level stack
1043 // frame, this will be null.)
1044 if (!ReferenceStmt) {
1045 assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind &&
1046 "Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext");
1047 LC = LC->getParent();
1048 }
1049
1050 const StackFrameContext *SFC = LC ? LC->getStackFrame() : nullptr;
1051 SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager());
1052
1053 for (auto I : CleanedState->get<ObjectsUnderConstruction>()) {
1054 if (SymbolRef Sym = I.second.getAsSymbol())
1055 SymReaper.markLive(Sym);
1056 if (const MemRegion *MR = I.second.getAsRegion())
1057 SymReaper.markLive(MR);
1058 }
1059
1060 getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
1061
1062 // Create a state in which dead bindings are removed from the environment
1063 // and the store. TODO: The function should just return new env and store,
1064 // not a new state.
1065 CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore(
1066 CleanedState, SFC, SymReaper);
1067
1068 // Process any special transfer function for dead symbols.
1069 // A tag to track convenience transitions, which can be removed at cleanup.
1070 static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node");
1071 // Call checkers with the non-cleaned state so that they could query the
1072 // values of the soon to be dead symbols.
1073 ExplodedNodeSet CheckedSet;
1074 getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper,
1075 DiagnosticStmt, *this, K);
1076
1077 // For each node in CheckedSet, generate CleanedNodes that have the
1078 // environment, the store, and the constraints cleaned up but have the
1079 // user-supplied states as the predecessors.
1080 StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx);
1081 for (const auto I : CheckedSet) {
1082 ProgramStateRef CheckerState = I->getState();
1083
1084 // The constraint manager has not been cleaned up yet, so clean up now.
1085 CheckerState =
1086 getConstraintManager().removeDeadBindings(CheckerState, SymReaper);
1087
1088 assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) &&
1089 "Checkers are not allowed to modify the Environment as a part of "
1090 "checkDeadSymbols processing.");
1091 assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) &&
1092 "Checkers are not allowed to modify the Store as a part of "
1093 "checkDeadSymbols processing.");
1094
1095 // Create a state based on CleanedState with CheckerState GDM and
1096 // generate a transition to that state.
1097 ProgramStateRef CleanedCheckerSt =
1098 StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
1099 Bldr.generateNode(DiagnosticStmt, I, CleanedCheckerSt, &cleanupTag, K);
1100 }
1101 }
1102
ProcessStmt(const Stmt * currStmt,ExplodedNode * Pred)1103 void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) {
1104 // Reclaim any unnecessary nodes in the ExplodedGraph.
1105 G.reclaimRecentlyAllocatedNodes();
1106
1107 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1108 currStmt->getBeginLoc(),
1109 "Error evaluating statement");
1110
1111 // Remove dead bindings and symbols.
1112 ExplodedNodeSet CleanedStates;
1113 if (shouldRemoveDeadBindings(AMgr, currStmt, Pred,
1114 Pred->getLocationContext())) {
1115 removeDead(Pred, CleanedStates, currStmt,
1116 Pred->getLocationContext());
1117 } else
1118 CleanedStates.Add(Pred);
1119
1120 // Visit the statement.
1121 ExplodedNodeSet Dst;
1122 for (const auto I : CleanedStates) {
1123 ExplodedNodeSet DstI;
1124 // Visit the statement.
1125 Visit(currStmt, I, DstI);
1126 Dst.insert(DstI);
1127 }
1128
1129 // Enqueue the new nodes onto the work list.
1130 Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
1131 }
1132
ProcessLoopExit(const Stmt * S,ExplodedNode * Pred)1133 void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
1134 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1135 S->getBeginLoc(),
1136 "Error evaluating end of the loop");
1137 ExplodedNodeSet Dst;
1138 Dst.Add(Pred);
1139 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1140 ProgramStateRef NewState = Pred->getState();
1141
1142 if(AMgr.options.ShouldUnrollLoops)
1143 NewState = processLoopEnd(S, NewState);
1144
1145 LoopExit PP(S, Pred->getLocationContext());
1146 Bldr.generateNode(PP, NewState, Pred);
1147 // Enqueue the new nodes onto the work list.
1148 Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
1149 }
1150
ProcessInitializer(const CFGInitializer CFGInit,ExplodedNode * Pred)1151 void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
1152 ExplodedNode *Pred) {
1153 const CXXCtorInitializer *BMI = CFGInit.getInitializer();
1154 const Expr *Init = BMI->getInit()->IgnoreImplicit();
1155 const LocationContext *LC = Pred->getLocationContext();
1156
1157 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1158 BMI->getSourceLocation(),
1159 "Error evaluating initializer");
1160
1161 // We don't clean up dead bindings here.
1162 const auto *stackFrame = cast<StackFrameContext>(Pred->getLocationContext());
1163 const auto *decl = cast<CXXConstructorDecl>(stackFrame->getDecl());
1164
1165 ProgramStateRef State = Pred->getState();
1166 SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
1167
1168 ExplodedNodeSet Tmp;
1169 SVal FieldLoc;
1170
1171 // Evaluate the initializer, if necessary
1172 if (BMI->isAnyMemberInitializer()) {
1173 // Constructors build the object directly in the field,
1174 // but non-objects must be copied in from the initializer.
1175 if (getObjectUnderConstruction(State, BMI, LC)) {
1176 // The field was directly constructed, so there is no need to bind.
1177 // But we still need to stop tracking the object under construction.
1178 State = finishObjectConstruction(State, BMI, LC);
1179 NodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
1180 PostStore PS(Init, LC, /*Loc*/ nullptr, /*tag*/ nullptr);
1181 Bldr.generateNode(PS, State, Pred);
1182 } else {
1183 const ValueDecl *Field;
1184 if (BMI->isIndirectMemberInitializer()) {
1185 Field = BMI->getIndirectMember();
1186 FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
1187 } else {
1188 Field = BMI->getMember();
1189 FieldLoc = State->getLValue(BMI->getMember(), thisVal);
1190 }
1191
1192 SVal InitVal;
1193 if (Init->getType()->isArrayType()) {
1194 // Handle arrays of trivial type. We can represent this with a
1195 // primitive load/copy from the base array region.
1196 const ArraySubscriptExpr *ASE;
1197 while ((ASE = dyn_cast<ArraySubscriptExpr>(Init)))
1198 Init = ASE->getBase()->IgnoreImplicit();
1199
1200 SVal LValue = State->getSVal(Init, stackFrame);
1201 if (!Field->getType()->isReferenceType())
1202 if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>())
1203 InitVal = State->getSVal(*LValueLoc);
1204
1205 // If we fail to get the value for some reason, use a symbolic value.
1206 if (InitVal.isUnknownOrUndef()) {
1207 SValBuilder &SVB = getSValBuilder();
1208 InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame,
1209 Field->getType(),
1210 currBldrCtx->blockCount());
1211 }
1212 } else {
1213 InitVal = State->getSVal(BMI->getInit(), stackFrame);
1214 }
1215
1216 PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
1217 evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
1218 }
1219 } else {
1220 assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
1221 Tmp.insert(Pred);
1222 // We already did all the work when visiting the CXXConstructExpr.
1223 }
1224
1225 // Construct PostInitializer nodes whether the state changed or not,
1226 // so that the diagnostics don't get confused.
1227 PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
1228 ExplodedNodeSet Dst;
1229 NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
1230 for (const auto I : Tmp) {
1231 ProgramStateRef State = I->getState();
1232 Bldr.generateNode(PP, State, I);
1233 }
1234
1235 // Enqueue the new nodes onto the work list.
1236 Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
1237 }
1238
1239 std::pair<ProgramStateRef, uint64_t>
prepareStateForArrayDestruction(const ProgramStateRef State,const MemRegion * Region,const QualType & ElementTy,const LocationContext * LCtx,SVal * ElementCountVal)1240 ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
1241 const MemRegion *Region,
1242 const QualType &ElementTy,
1243 const LocationContext *LCtx,
1244 SVal *ElementCountVal) {
1245 assert(Region != nullptr && "Not-null region expected");
1246
1247 QualType Ty = ElementTy.getDesugaredType(getContext());
1248 while (const auto *NTy = dyn_cast<ArrayType>(Ty))
1249 Ty = NTy->getElementType().getDesugaredType(getContext());
1250
1251 auto ElementCount = getDynamicElementCount(State, Region, svalBuilder, Ty);
1252
1253 if (ElementCountVal)
1254 *ElementCountVal = ElementCount;
1255
1256 // Note: the destructors are called in reverse order.
1257 unsigned Idx = 0;
1258 if (auto OptionalIdx = getPendingArrayDestruction(State, LCtx)) {
1259 Idx = *OptionalIdx;
1260 } else {
1261 // The element count is either unknown, or an SVal that's not an integer.
1262 if (!ElementCount.isConstant())
1263 return {State, 0};
1264
1265 Idx = ElementCount.getAsInteger()->getLimitedValue();
1266 }
1267
1268 if (Idx == 0)
1269 return {State, 0};
1270
1271 --Idx;
1272
1273 return {setPendingArrayDestruction(State, LCtx, Idx), Idx};
1274 }
1275
ProcessImplicitDtor(const CFGImplicitDtor D,ExplodedNode * Pred)1276 void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
1277 ExplodedNode *Pred) {
1278 ExplodedNodeSet Dst;
1279 switch (D.getKind()) {
1280 case CFGElement::AutomaticObjectDtor:
1281 ProcessAutomaticObjDtor(D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
1282 break;
1283 case CFGElement::BaseDtor:
1284 ProcessBaseDtor(D.castAs<CFGBaseDtor>(), Pred, Dst);
1285 break;
1286 case CFGElement::MemberDtor:
1287 ProcessMemberDtor(D.castAs<CFGMemberDtor>(), Pred, Dst);
1288 break;
1289 case CFGElement::TemporaryDtor:
1290 ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst);
1291 break;
1292 case CFGElement::DeleteDtor:
1293 ProcessDeleteDtor(D.castAs<CFGDeleteDtor>(), Pred, Dst);
1294 break;
1295 default:
1296 llvm_unreachable("Unexpected dtor kind.");
1297 }
1298
1299 // Enqueue the new nodes onto the work list.
1300 Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
1301 }
1302
ProcessNewAllocator(const CXXNewExpr * NE,ExplodedNode * Pred)1303 void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
1304 ExplodedNode *Pred) {
1305 ExplodedNodeSet Dst;
1306 AnalysisManager &AMgr = getAnalysisManager();
1307 AnalyzerOptions &Opts = AMgr.options;
1308 // TODO: We're not evaluating allocators for all cases just yet as
1309 // we're not handling the return value correctly, which causes false
1310 // positives when the alpha.cplusplus.NewDeleteLeaks check is on.
1311 if (Opts.MayInlineCXXAllocator)
1312 VisitCXXNewAllocatorCall(NE, Pred, Dst);
1313 else {
1314 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1315 const LocationContext *LCtx = Pred->getLocationContext();
1316 PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx);
1317 Bldr.generateNode(PP, Pred->getState(), Pred);
1318 }
1319 Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
1320 }
1321
ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,ExplodedNode * Pred,ExplodedNodeSet & Dst)1322 void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
1323 ExplodedNode *Pred,
1324 ExplodedNodeSet &Dst) {
1325 const auto *DtorDecl = Dtor.getDestructorDecl(getContext());
1326 const VarDecl *varDecl = Dtor.getVarDecl();
1327 QualType varType = varDecl->getType();
1328
1329 ProgramStateRef state = Pred->getState();
1330 const LocationContext *LCtx = Pred->getLocationContext();
1331
1332 SVal dest = state->getLValue(varDecl, LCtx);
1333 const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
1334
1335 if (varType->isReferenceType()) {
1336 const MemRegion *ValueRegion = state->getSVal(Region).getAsRegion();
1337 if (!ValueRegion) {
1338 // FIXME: This should not happen. The language guarantees a presence
1339 // of a valid initializer here, so the reference shall not be undefined.
1340 // It seems that we're calling destructors over variables that
1341 // were not initialized yet.
1342 return;
1343 }
1344 Region = ValueRegion->getBaseRegion();
1345 varType = cast<TypedValueRegion>(Region)->getValueType();
1346 }
1347
1348 unsigned Idx = 0;
1349 if (isa<ArrayType>(varType)) {
1350 SVal ElementCount;
1351 std::tie(state, Idx) = prepareStateForArrayDestruction(
1352 state, Region, varType, LCtx, &ElementCount);
1353
1354 if (ElementCount.isConstant()) {
1355 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1356 assert(ArrayLength &&
1357 "An automatic dtor for a 0 length array shouldn't be triggered!");
1358
1359 // Still handle this case if we don't have assertions enabled.
1360 if (!ArrayLength) {
1361 static SimpleProgramPointTag PT(
1362 "ExprEngine", "Skipping automatic 0 length array destruction, "
1363 "which shouldn't be in the CFG.");
1364 PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
1365 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1366 Bldr.generateSink(PP, Pred->getState(), Pred);
1367 return;
1368 }
1369 }
1370 }
1371
1372 EvalCallOptions CallOpts;
1373 Region = makeElementRegion(state, loc::MemRegionVal(Region), varType,
1374 CallOpts.IsArrayCtorOrDtor, Idx)
1375 .getAsRegion();
1376
1377 NodeBuilder Bldr(Pred, Dst, getBuilderContext());
1378
1379 static SimpleProgramPointTag PT("ExprEngine",
1380 "Prepare for object destruction");
1381 PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
1382 Pred = Bldr.generateNode(PP, state, Pred);
1383
1384 if (!Pred)
1385 return;
1386 Bldr.takeNodes(Pred);
1387
1388 VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(),
1389 /*IsBase=*/false, Pred, Dst, CallOpts);
1390 }
1391
ProcessDeleteDtor(const CFGDeleteDtor Dtor,ExplodedNode * Pred,ExplodedNodeSet & Dst)1392 void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
1393 ExplodedNode *Pred,
1394 ExplodedNodeSet &Dst) {
1395 ProgramStateRef State = Pred->getState();
1396 const LocationContext *LCtx = Pred->getLocationContext();
1397 const CXXDeleteExpr *DE = Dtor.getDeleteExpr();
1398 const Stmt *Arg = DE->getArgument();
1399 QualType DTy = DE->getDestroyedType();
1400 SVal ArgVal = State->getSVal(Arg, LCtx);
1401
1402 // If the argument to delete is known to be a null value,
1403 // don't run destructor.
1404 if (State->isNull(ArgVal).isConstrainedTrue()) {
1405 QualType BTy = getContext().getBaseElementType(DTy);
1406 const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
1407 const CXXDestructorDecl *Dtor = RD->getDestructor();
1408
1409 PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx);
1410 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1411 Bldr.generateNode(PP, Pred->getState(), Pred);
1412 return;
1413 }
1414
1415 auto getDtorDecl = [](const QualType &DTy) {
1416 const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl();
1417 return RD->getDestructor();
1418 };
1419
1420 unsigned Idx = 0;
1421 EvalCallOptions CallOpts;
1422 const MemRegion *ArgR = ArgVal.getAsRegion();
1423
1424 if (DE->isArrayForm()) {
1425 CallOpts.IsArrayCtorOrDtor = true;
1426 // Yes, it may even be a multi-dimensional array.
1427 while (const auto *AT = getContext().getAsArrayType(DTy))
1428 DTy = AT->getElementType();
1429
1430 if (ArgR) {
1431 SVal ElementCount;
1432 std::tie(State, Idx) = prepareStateForArrayDestruction(
1433 State, ArgR, DTy, LCtx, &ElementCount);
1434
1435 // If we're about to destruct a 0 length array, don't run any of the
1436 // destructors.
1437 if (ElementCount.isConstant() &&
1438 ElementCount.getAsInteger()->getLimitedValue() == 0) {
1439
1440 static SimpleProgramPointTag PT(
1441 "ExprEngine", "Skipping 0 length array delete destruction");
1442 PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
1443 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1444 Bldr.generateNode(PP, Pred->getState(), Pred);
1445 return;
1446 }
1447
1448 ArgR = State->getLValue(DTy, svalBuilder.makeArrayIndex(Idx), ArgVal)
1449 .getAsRegion();
1450 }
1451 }
1452
1453 NodeBuilder Bldr(Pred, Dst, getBuilderContext());
1454 static SimpleProgramPointTag PT("ExprEngine",
1455 "Prepare for object destruction");
1456 PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
1457 Pred = Bldr.generateNode(PP, State, Pred);
1458
1459 if (!Pred)
1460 return;
1461 Bldr.takeNodes(Pred);
1462
1463 VisitCXXDestructor(DTy, ArgR, DE, /*IsBase=*/false, Pred, Dst, CallOpts);
1464 }
1465
ProcessBaseDtor(const CFGBaseDtor D,ExplodedNode * Pred,ExplodedNodeSet & Dst)1466 void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
1467 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1468 const LocationContext *LCtx = Pred->getLocationContext();
1469
1470 const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
1471 Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor,
1472 LCtx->getStackFrame());
1473 SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
1474
1475 // Create the base object region.
1476 const CXXBaseSpecifier *Base = D.getBaseSpecifier();
1477 QualType BaseTy = Base->getType();
1478 SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
1479 Base->isVirtual());
1480
1481 EvalCallOptions CallOpts;
1482 VisitCXXDestructor(BaseTy, BaseVal.getAsRegion(), CurDtor->getBody(),
1483 /*IsBase=*/true, Pred, Dst, CallOpts);
1484 }
1485
ProcessMemberDtor(const CFGMemberDtor D,ExplodedNode * Pred,ExplodedNodeSet & Dst)1486 void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
1487 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1488 const auto *DtorDecl = D.getDestructorDecl(getContext());
1489 const FieldDecl *Member = D.getFieldDecl();
1490 QualType T = Member->getType();
1491 ProgramStateRef State = Pred->getState();
1492 const LocationContext *LCtx = Pred->getLocationContext();
1493
1494 const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
1495 Loc ThisStorageLoc =
1496 getSValBuilder().getCXXThis(CurDtor, LCtx->getStackFrame());
1497 Loc ThisLoc = State->getSVal(ThisStorageLoc).castAs<Loc>();
1498 SVal FieldVal = State->getLValue(Member, ThisLoc);
1499
1500 unsigned Idx = 0;
1501 if (isa<ArrayType>(T)) {
1502 SVal ElementCount;
1503 std::tie(State, Idx) = prepareStateForArrayDestruction(
1504 State, FieldVal.getAsRegion(), T, LCtx, &ElementCount);
1505
1506 if (ElementCount.isConstant()) {
1507 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1508 assert(ArrayLength &&
1509 "A member dtor for a 0 length array shouldn't be triggered!");
1510
1511 // Still handle this case if we don't have assertions enabled.
1512 if (!ArrayLength) {
1513 static SimpleProgramPointTag PT(
1514 "ExprEngine", "Skipping member 0 length array destruction, which "
1515 "shouldn't be in the CFG.");
1516 PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
1517 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1518 Bldr.generateSink(PP, Pred->getState(), Pred);
1519 return;
1520 }
1521 }
1522 }
1523
1524 EvalCallOptions CallOpts;
1525 FieldVal =
1526 makeElementRegion(State, FieldVal, T, CallOpts.IsArrayCtorOrDtor, Idx);
1527
1528 NodeBuilder Bldr(Pred, Dst, getBuilderContext());
1529
1530 static SimpleProgramPointTag PT("ExprEngine",
1531 "Prepare for object destruction");
1532 PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
1533 Pred = Bldr.generateNode(PP, State, Pred);
1534
1535 if (!Pred)
1536 return;
1537 Bldr.takeNodes(Pred);
1538
1539 VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(),
1540 /*IsBase=*/false, Pred, Dst, CallOpts);
1541 }
1542
ProcessTemporaryDtor(const CFGTemporaryDtor D,ExplodedNode * Pred,ExplodedNodeSet & Dst)1543 void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
1544 ExplodedNode *Pred,
1545 ExplodedNodeSet &Dst) {
1546 const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr();
1547 ProgramStateRef State = Pred->getState();
1548 const LocationContext *LC = Pred->getLocationContext();
1549 const MemRegion *MR = nullptr;
1550
1551 if (std::optional<SVal> V = getObjectUnderConstruction(
1552 State, D.getBindTemporaryExpr(), Pred->getLocationContext())) {
1553 // FIXME: Currently we insert temporary destructors for default parameters,
1554 // but we don't insert the constructors, so the entry in
1555 // ObjectsUnderConstruction may be missing.
1556 State = finishObjectConstruction(State, D.getBindTemporaryExpr(),
1557 Pred->getLocationContext());
1558 MR = V->getAsRegion();
1559 }
1560
1561 // If copy elision has occurred, and the constructor corresponding to the
1562 // destructor was elided, we need to skip the destructor as well.
1563 if (isDestructorElided(State, BTE, LC)) {
1564 State = cleanupElidedDestructor(State, BTE, LC);
1565 NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1566 PostImplicitCall PP(D.getDestructorDecl(getContext()),
1567 D.getBindTemporaryExpr()->getBeginLoc(),
1568 Pred->getLocationContext());
1569 Bldr.generateNode(PP, State, Pred);
1570 return;
1571 }
1572
1573 ExplodedNodeSet CleanDtorState;
1574 StmtNodeBuilder StmtBldr(Pred, CleanDtorState, *currBldrCtx);
1575 StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State);
1576
1577 QualType T = D.getBindTemporaryExpr()->getSubExpr()->getType();
1578 // FIXME: Currently CleanDtorState can be empty here due to temporaries being
1579 // bound to default parameters.
1580 assert(CleanDtorState.size() <= 1);
1581 ExplodedNode *CleanPred =
1582 CleanDtorState.empty() ? Pred : *CleanDtorState.begin();
1583
1584 EvalCallOptions CallOpts;
1585 CallOpts.IsTemporaryCtorOrDtor = true;
1586 if (!MR) {
1587 // FIXME: If we have no MR, we still need to unwrap the array to avoid
1588 // destroying the whole array at once.
1589 //
1590 // For this case there is no universal solution as there is no way to
1591 // directly create an array of temporary objects. There are some expressions
1592 // however which can create temporary objects and have an array type.
1593 //
1594 // E.g.: std::initializer_list<S>{S(), S()};
1595 //
1596 // The expression above has a type of 'const struct S[2]' but it's a single
1597 // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()'
1598 // objects will be called anyway, because they are 2 separate objects in 2
1599 // separate clusters, i.e.: not an array.
1600 //
1601 // Now the 'std::initializer_list<>' is not an array either even though it
1602 // has the type of an array. The point is, we only want to invoke the
1603 // destructor for the initializer list once not twice or so.
1604 while (const ArrayType *AT = getContext().getAsArrayType(T)) {
1605 T = AT->getElementType();
1606
1607 // FIXME: Enable this flag once we handle this case properly.
1608 // CallOpts.IsArrayCtorOrDtor = true;
1609 }
1610 } else {
1611 // FIXME: We'd eventually need to makeElementRegion() trick here,
1612 // but for now we don't have the respective construction contexts,
1613 // so MR would always be null in this case. Do nothing for now.
1614 }
1615 VisitCXXDestructor(T, MR, D.getBindTemporaryExpr(),
1616 /*IsBase=*/false, CleanPred, Dst, CallOpts);
1617 }
1618
processCleanupTemporaryBranch(const CXXBindTemporaryExpr * BTE,NodeBuilderContext & BldCtx,ExplodedNode * Pred,ExplodedNodeSet & Dst,const CFGBlock * DstT,const CFGBlock * DstF)1619 void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
1620 NodeBuilderContext &BldCtx,
1621 ExplodedNode *Pred,
1622 ExplodedNodeSet &Dst,
1623 const CFGBlock *DstT,
1624 const CFGBlock *DstF) {
1625 BranchNodeBuilder TempDtorBuilder(Pred, Dst, BldCtx, DstT, DstF);
1626 ProgramStateRef State = Pred->getState();
1627 const LocationContext *LC = Pred->getLocationContext();
1628 if (getObjectUnderConstruction(State, BTE, LC)) {
1629 TempDtorBuilder.markInfeasible(false);
1630 TempDtorBuilder.generateNode(State, true, Pred);
1631 } else {
1632 TempDtorBuilder.markInfeasible(true);
1633 TempDtorBuilder.generateNode(State, false, Pred);
1634 }
1635 }
1636
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * BTE,ExplodedNodeSet & PreVisit,ExplodedNodeSet & Dst)1637 void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
1638 ExplodedNodeSet &PreVisit,
1639 ExplodedNodeSet &Dst) {
1640 // This is a fallback solution in case we didn't have a construction
1641 // context when we were constructing the temporary. Otherwise the map should
1642 // have been populated there.
1643 if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
1644 // In case we don't have temporary destructors in the CFG, do not mark
1645 // the initialization - we would otherwise never clean it up.
1646 Dst = PreVisit;
1647 return;
1648 }
1649 StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx);
1650 for (ExplodedNode *Node : PreVisit) {
1651 ProgramStateRef State = Node->getState();
1652 const LocationContext *LC = Node->getLocationContext();
1653 if (!getObjectUnderConstruction(State, BTE, LC)) {
1654 // FIXME: Currently the state might also already contain the marker due to
1655 // incorrect handling of temporaries bound to default parameters; for
1656 // those, we currently skip the CXXBindTemporaryExpr but rely on adding
1657 // temporary destructor nodes.
1658 State = addObjectUnderConstruction(State, BTE, LC, UnknownVal());
1659 }
1660 StmtBldr.generateNode(BTE, Node, State);
1661 }
1662 }
1663
escapeValues(ProgramStateRef State,ArrayRef<SVal> Vs,PointerEscapeKind K,const CallEvent * Call) const1664 ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
1665 ArrayRef<SVal> Vs,
1666 PointerEscapeKind K,
1667 const CallEvent *Call) const {
1668 class CollectReachableSymbolsCallback final : public SymbolVisitor {
1669 InvalidatedSymbols &Symbols;
1670
1671 public:
1672 explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
1673 : Symbols(Symbols) {}
1674
1675 const InvalidatedSymbols &getSymbols() const { return Symbols; }
1676
1677 bool VisitSymbol(SymbolRef Sym) override {
1678 Symbols.insert(Sym);
1679 return true;
1680 }
1681 };
1682 InvalidatedSymbols Symbols;
1683 CollectReachableSymbolsCallback CallBack(Symbols);
1684 for (SVal V : Vs)
1685 State->scanReachableSymbols(V, CallBack);
1686
1687 return getCheckerManager().runCheckersForPointerEscape(
1688 State, CallBack.getSymbols(), Call, K, nullptr);
1689 }
1690
Visit(const Stmt * S,ExplodedNode * Pred,ExplodedNodeSet & DstTop)1691 void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
1692 ExplodedNodeSet &DstTop) {
1693 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1694 S->getBeginLoc(), "Error evaluating statement");
1695 ExplodedNodeSet Dst;
1696 StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
1697
1698 assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
1699
1700 switch (S->getStmtClass()) {
1701 // C++, OpenMP and ARC stuff we don't support yet.
1702 case Stmt::CXXDependentScopeMemberExprClass:
1703 case Stmt::CXXTryStmtClass:
1704 case Stmt::CXXTypeidExprClass:
1705 case Stmt::CXXUuidofExprClass:
1706 case Stmt::CXXFoldExprClass:
1707 case Stmt::MSPropertyRefExprClass:
1708 case Stmt::MSPropertySubscriptExprClass:
1709 case Stmt::CXXUnresolvedConstructExprClass:
1710 case Stmt::DependentScopeDeclRefExprClass:
1711 case Stmt::ArrayTypeTraitExprClass:
1712 case Stmt::ExpressionTraitExprClass:
1713 case Stmt::UnresolvedLookupExprClass:
1714 case Stmt::UnresolvedMemberExprClass:
1715 case Stmt::TypoExprClass:
1716 case Stmt::RecoveryExprClass:
1717 case Stmt::CXXNoexceptExprClass:
1718 case Stmt::PackExpansionExprClass:
1719 case Stmt::SubstNonTypeTemplateParmPackExprClass:
1720 case Stmt::FunctionParmPackExprClass:
1721 case Stmt::CoroutineBodyStmtClass:
1722 case Stmt::CoawaitExprClass:
1723 case Stmt::DependentCoawaitExprClass:
1724 case Stmt::CoreturnStmtClass:
1725 case Stmt::CoyieldExprClass:
1726 case Stmt::SEHTryStmtClass:
1727 case Stmt::SEHExceptStmtClass:
1728 case Stmt::SEHLeaveStmtClass:
1729 case Stmt::SEHFinallyStmtClass:
1730 case Stmt::OMPCanonicalLoopClass:
1731 case Stmt::OMPParallelDirectiveClass:
1732 case Stmt::OMPSimdDirectiveClass:
1733 case Stmt::OMPForDirectiveClass:
1734 case Stmt::OMPForSimdDirectiveClass:
1735 case Stmt::OMPSectionsDirectiveClass:
1736 case Stmt::OMPSectionDirectiveClass:
1737 case Stmt::OMPSingleDirectiveClass:
1738 case Stmt::OMPMasterDirectiveClass:
1739 case Stmt::OMPCriticalDirectiveClass:
1740 case Stmt::OMPParallelForDirectiveClass:
1741 case Stmt::OMPParallelForSimdDirectiveClass:
1742 case Stmt::OMPParallelSectionsDirectiveClass:
1743 case Stmt::OMPParallelMasterDirectiveClass:
1744 case Stmt::OMPParallelMaskedDirectiveClass:
1745 case Stmt::OMPTaskDirectiveClass:
1746 case Stmt::OMPTaskyieldDirectiveClass:
1747 case Stmt::OMPBarrierDirectiveClass:
1748 case Stmt::OMPTaskwaitDirectiveClass:
1749 case Stmt::OMPErrorDirectiveClass:
1750 case Stmt::OMPTaskgroupDirectiveClass:
1751 case Stmt::OMPFlushDirectiveClass:
1752 case Stmt::OMPDepobjDirectiveClass:
1753 case Stmt::OMPScanDirectiveClass:
1754 case Stmt::OMPOrderedDirectiveClass:
1755 case Stmt::OMPAtomicDirectiveClass:
1756 case Stmt::OMPTargetDirectiveClass:
1757 case Stmt::OMPTargetDataDirectiveClass:
1758 case Stmt::OMPTargetEnterDataDirectiveClass:
1759 case Stmt::OMPTargetExitDataDirectiveClass:
1760 case Stmt::OMPTargetParallelDirectiveClass:
1761 case Stmt::OMPTargetParallelForDirectiveClass:
1762 case Stmt::OMPTargetUpdateDirectiveClass:
1763 case Stmt::OMPTeamsDirectiveClass:
1764 case Stmt::OMPCancellationPointDirectiveClass:
1765 case Stmt::OMPCancelDirectiveClass:
1766 case Stmt::OMPTaskLoopDirectiveClass:
1767 case Stmt::OMPTaskLoopSimdDirectiveClass:
1768 case Stmt::OMPMasterTaskLoopDirectiveClass:
1769 case Stmt::OMPMaskedTaskLoopDirectiveClass:
1770 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
1771 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
1772 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
1773 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
1774 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
1775 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
1776 case Stmt::OMPDistributeDirectiveClass:
1777 case Stmt::OMPDistributeParallelForDirectiveClass:
1778 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
1779 case Stmt::OMPDistributeSimdDirectiveClass:
1780 case Stmt::OMPTargetParallelForSimdDirectiveClass:
1781 case Stmt::OMPTargetSimdDirectiveClass:
1782 case Stmt::OMPTeamsDistributeDirectiveClass:
1783 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
1784 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
1785 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
1786 case Stmt::OMPTargetTeamsDirectiveClass:
1787 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
1788 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
1789 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
1790 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
1791 case Stmt::OMPTileDirectiveClass:
1792 case Stmt::OMPInteropDirectiveClass:
1793 case Stmt::OMPDispatchDirectiveClass:
1794 case Stmt::OMPMaskedDirectiveClass:
1795 case Stmt::OMPGenericLoopDirectiveClass:
1796 case Stmt::OMPTeamsGenericLoopDirectiveClass:
1797 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
1798 case Stmt::OMPParallelGenericLoopDirectiveClass:
1799 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
1800 case Stmt::CapturedStmtClass:
1801 case Stmt::OMPUnrollDirectiveClass:
1802 case Stmt::OMPMetaDirectiveClass: {
1803 const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
1804 Engine.addAbortedBlock(node, currBldrCtx->getBlock());
1805 break;
1806 }
1807
1808 case Stmt::ParenExprClass:
1809 llvm_unreachable("ParenExprs already handled.");
1810 case Stmt::GenericSelectionExprClass:
1811 llvm_unreachable("GenericSelectionExprs already handled.");
1812 // Cases that should never be evaluated simply because they shouldn't
1813 // appear in the CFG.
1814 case Stmt::BreakStmtClass:
1815 case Stmt::CaseStmtClass:
1816 case Stmt::CompoundStmtClass:
1817 case Stmt::ContinueStmtClass:
1818 case Stmt::CXXForRangeStmtClass:
1819 case Stmt::DefaultStmtClass:
1820 case Stmt::DoStmtClass:
1821 case Stmt::ForStmtClass:
1822 case Stmt::GotoStmtClass:
1823 case Stmt::IfStmtClass:
1824 case Stmt::IndirectGotoStmtClass:
1825 case Stmt::LabelStmtClass:
1826 case Stmt::NoStmtClass:
1827 case Stmt::NullStmtClass:
1828 case Stmt::SwitchStmtClass:
1829 case Stmt::WhileStmtClass:
1830 case Expr::MSDependentExistsStmtClass:
1831 llvm_unreachable("Stmt should not be in analyzer evaluation loop");
1832 case Stmt::ImplicitValueInitExprClass:
1833 // These nodes are shared in the CFG and would case caching out.
1834 // Moreover, no additional evaluation required for them, the
1835 // analyzer can reconstruct these values from the AST.
1836 llvm_unreachable("Should be pruned from CFG");
1837
1838 case Stmt::ObjCSubscriptRefExprClass:
1839 case Stmt::ObjCPropertyRefExprClass:
1840 llvm_unreachable("These are handled by PseudoObjectExpr");
1841
1842 case Stmt::GNUNullExprClass: {
1843 // GNU __null is a pointer-width integer, not an actual pointer.
1844 ProgramStateRef state = Pred->getState();
1845 state = state->BindExpr(
1846 S, Pred->getLocationContext(),
1847 svalBuilder.makeIntValWithWidth(getContext().VoidPtrTy, 0));
1848 Bldr.generateNode(S, Pred, state);
1849 break;
1850 }
1851
1852 case Stmt::ObjCAtSynchronizedStmtClass:
1853 Bldr.takeNodes(Pred);
1854 VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
1855 Bldr.addNodes(Dst);
1856 break;
1857
1858 case Expr::ConstantExprClass:
1859 case Stmt::ExprWithCleanupsClass:
1860 // Handled due to fully linearised CFG.
1861 break;
1862
1863 case Stmt::CXXBindTemporaryExprClass: {
1864 Bldr.takeNodes(Pred);
1865 ExplodedNodeSet PreVisit;
1866 getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
1867 ExplodedNodeSet Next;
1868 VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next);
1869 getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this);
1870 Bldr.addNodes(Dst);
1871 break;
1872 }
1873
1874 case Stmt::ArrayInitLoopExprClass:
1875 Bldr.takeNodes(Pred);
1876 VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), Pred, Dst);
1877 Bldr.addNodes(Dst);
1878 break;
1879 // Cases not handled yet; but will handle some day.
1880 case Stmt::DesignatedInitExprClass:
1881 case Stmt::DesignatedInitUpdateExprClass:
1882 case Stmt::ArrayInitIndexExprClass:
1883 case Stmt::ExtVectorElementExprClass:
1884 case Stmt::ImaginaryLiteralClass:
1885 case Stmt::ObjCAtCatchStmtClass:
1886 case Stmt::ObjCAtFinallyStmtClass:
1887 case Stmt::ObjCAtTryStmtClass:
1888 case Stmt::ObjCAutoreleasePoolStmtClass:
1889 case Stmt::ObjCEncodeExprClass:
1890 case Stmt::ObjCIsaExprClass:
1891 case Stmt::ObjCProtocolExprClass:
1892 case Stmt::ObjCSelectorExprClass:
1893 case Stmt::ParenListExprClass:
1894 case Stmt::ShuffleVectorExprClass:
1895 case Stmt::ConvertVectorExprClass:
1896 case Stmt::VAArgExprClass:
1897 case Stmt::CUDAKernelCallExprClass:
1898 case Stmt::OpaqueValueExprClass:
1899 case Stmt::AsTypeExprClass:
1900 case Stmt::ConceptSpecializationExprClass:
1901 case Stmt::CXXRewrittenBinaryOperatorClass:
1902 case Stmt::RequiresExprClass:
1903 case Expr::CXXParenListInitExprClass:
1904 // Fall through.
1905
1906 // Cases we intentionally don't evaluate, since they don't need
1907 // to be explicitly evaluated.
1908 case Stmt::PredefinedExprClass:
1909 case Stmt::AddrLabelExprClass:
1910 case Stmt::AttributedStmtClass:
1911 case Stmt::IntegerLiteralClass:
1912 case Stmt::FixedPointLiteralClass:
1913 case Stmt::CharacterLiteralClass:
1914 case Stmt::CXXScalarValueInitExprClass:
1915 case Stmt::CXXBoolLiteralExprClass:
1916 case Stmt::ObjCBoolLiteralExprClass:
1917 case Stmt::ObjCAvailabilityCheckExprClass:
1918 case Stmt::FloatingLiteralClass:
1919 case Stmt::NoInitExprClass:
1920 case Stmt::SizeOfPackExprClass:
1921 case Stmt::StringLiteralClass:
1922 case Stmt::SourceLocExprClass:
1923 case Stmt::ObjCStringLiteralClass:
1924 case Stmt::CXXPseudoDestructorExprClass:
1925 case Stmt::SubstNonTypeTemplateParmExprClass:
1926 case Stmt::CXXNullPtrLiteralExprClass:
1927 case Stmt::OMPArraySectionExprClass:
1928 case Stmt::OMPArrayShapingExprClass:
1929 case Stmt::OMPIteratorExprClass:
1930 case Stmt::SYCLUniqueStableNameExprClass:
1931 case Stmt::TypeTraitExprClass: {
1932 Bldr.takeNodes(Pred);
1933 ExplodedNodeSet preVisit;
1934 getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
1935 getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
1936 Bldr.addNodes(Dst);
1937 break;
1938 }
1939
1940 case Stmt::CXXDefaultArgExprClass:
1941 case Stmt::CXXDefaultInitExprClass: {
1942 Bldr.takeNodes(Pred);
1943 ExplodedNodeSet PreVisit;
1944 getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
1945
1946 ExplodedNodeSet Tmp;
1947 StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
1948
1949 const Expr *ArgE;
1950 if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S))
1951 ArgE = DefE->getExpr();
1952 else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S))
1953 ArgE = DefE->getExpr();
1954 else
1955 llvm_unreachable("unknown constant wrapper kind");
1956
1957 bool IsTemporary = false;
1958 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
1959 ArgE = MTE->getSubExpr();
1960 IsTemporary = true;
1961 }
1962
1963 std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
1964 if (!ConstantVal)
1965 ConstantVal = UnknownVal();
1966
1967 const LocationContext *LCtx = Pred->getLocationContext();
1968 for (const auto I : PreVisit) {
1969 ProgramStateRef State = I->getState();
1970 State = State->BindExpr(S, LCtx, *ConstantVal);
1971 if (IsTemporary)
1972 State = createTemporaryRegionIfNeeded(State, LCtx,
1973 cast<Expr>(S),
1974 cast<Expr>(S));
1975 Bldr2.generateNode(S, I, State);
1976 }
1977
1978 getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
1979 Bldr.addNodes(Dst);
1980 break;
1981 }
1982
1983 // Cases we evaluate as opaque expressions, conjuring a symbol.
1984 case Stmt::CXXStdInitializerListExprClass:
1985 case Expr::ObjCArrayLiteralClass:
1986 case Expr::ObjCDictionaryLiteralClass:
1987 case Expr::ObjCBoxedExprClass: {
1988 Bldr.takeNodes(Pred);
1989
1990 ExplodedNodeSet preVisit;
1991 getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
1992
1993 ExplodedNodeSet Tmp;
1994 StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
1995
1996 const auto *Ex = cast<Expr>(S);
1997 QualType resultType = Ex->getType();
1998
1999 for (const auto N : preVisit) {
2000 const LocationContext *LCtx = N->getLocationContext();
2001 SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
2002 resultType,
2003 currBldrCtx->blockCount());
2004 ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result);
2005
2006 // Escape pointers passed into the list, unless it's an ObjC boxed
2007 // expression which is not a boxable C structure.
2008 if (!(isa<ObjCBoxedExpr>(Ex) &&
2009 !cast<ObjCBoxedExpr>(Ex)->getSubExpr()
2010 ->getType()->isRecordType()))
2011 for (auto Child : Ex->children()) {
2012 assert(Child);
2013 SVal Val = State->getSVal(Child, LCtx);
2014 State = escapeValues(State, Val, PSK_EscapeOther);
2015 }
2016
2017 Bldr2.generateNode(S, N, State);
2018 }
2019
2020 getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
2021 Bldr.addNodes(Dst);
2022 break;
2023 }
2024
2025 case Stmt::ArraySubscriptExprClass:
2026 Bldr.takeNodes(Pred);
2027 VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
2028 Bldr.addNodes(Dst);
2029 break;
2030
2031 case Stmt::MatrixSubscriptExprClass:
2032 llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
2033 break;
2034
2035 case Stmt::GCCAsmStmtClass:
2036 Bldr.takeNodes(Pred);
2037 VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
2038 Bldr.addNodes(Dst);
2039 break;
2040
2041 case Stmt::MSAsmStmtClass:
2042 Bldr.takeNodes(Pred);
2043 VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
2044 Bldr.addNodes(Dst);
2045 break;
2046
2047 case Stmt::BlockExprClass:
2048 Bldr.takeNodes(Pred);
2049 VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
2050 Bldr.addNodes(Dst);
2051 break;
2052
2053 case Stmt::LambdaExprClass:
2054 if (AMgr.options.ShouldInlineLambdas) {
2055 Bldr.takeNodes(Pred);
2056 VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
2057 Bldr.addNodes(Dst);
2058 } else {
2059 const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
2060 Engine.addAbortedBlock(node, currBldrCtx->getBlock());
2061 }
2062 break;
2063
2064 case Stmt::BinaryOperatorClass: {
2065 const auto *B = cast<BinaryOperator>(S);
2066 if (B->isLogicalOp()) {
2067 Bldr.takeNodes(Pred);
2068 VisitLogicalExpr(B, Pred, Dst);
2069 Bldr.addNodes(Dst);
2070 break;
2071 }
2072 else if (B->getOpcode() == BO_Comma) {
2073 ProgramStateRef state = Pred->getState();
2074 Bldr.generateNode(B, Pred,
2075 state->BindExpr(B, Pred->getLocationContext(),
2076 state->getSVal(B->getRHS(),
2077 Pred->getLocationContext())));
2078 break;
2079 }
2080
2081 Bldr.takeNodes(Pred);
2082
2083 if (AMgr.options.ShouldEagerlyAssume &&
2084 (B->isRelationalOp() || B->isEqualityOp())) {
2085 ExplodedNodeSet Tmp;
2086 VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
2087 evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
2088 }
2089 else
2090 VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
2091
2092 Bldr.addNodes(Dst);
2093 break;
2094 }
2095
2096 case Stmt::CXXOperatorCallExprClass: {
2097 const auto *OCE = cast<CXXOperatorCallExpr>(S);
2098
2099 // For instance method operators, make sure the 'this' argument has a
2100 // valid region.
2101 const Decl *Callee = OCE->getCalleeDecl();
2102 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
2103 if (MD->isInstance()) {
2104 ProgramStateRef State = Pred->getState();
2105 const LocationContext *LCtx = Pred->getLocationContext();
2106 ProgramStateRef NewState =
2107 createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
2108 if (NewState != State) {
2109 Pred = Bldr.generateNode(OCE, Pred, NewState, /*tag=*/nullptr,
2110 ProgramPoint::PreStmtKind);
2111 // Did we cache out?
2112 if (!Pred)
2113 break;
2114 }
2115 }
2116 }
2117 // FALLTHROUGH
2118 [[fallthrough]];
2119 }
2120
2121 case Stmt::CallExprClass:
2122 case Stmt::CXXMemberCallExprClass:
2123 case Stmt::UserDefinedLiteralClass:
2124 Bldr.takeNodes(Pred);
2125 VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
2126 Bldr.addNodes(Dst);
2127 break;
2128
2129 case Stmt::CXXCatchStmtClass:
2130 Bldr.takeNodes(Pred);
2131 VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
2132 Bldr.addNodes(Dst);
2133 break;
2134
2135 case Stmt::CXXTemporaryObjectExprClass:
2136 case Stmt::CXXConstructExprClass:
2137 Bldr.takeNodes(Pred);
2138 VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
2139 Bldr.addNodes(Dst);
2140 break;
2141
2142 case Stmt::CXXInheritedCtorInitExprClass:
2143 Bldr.takeNodes(Pred);
2144 VisitCXXInheritedCtorInitExpr(cast<CXXInheritedCtorInitExpr>(S), Pred,
2145 Dst);
2146 Bldr.addNodes(Dst);
2147 break;
2148
2149 case Stmt::CXXNewExprClass: {
2150 Bldr.takeNodes(Pred);
2151
2152 ExplodedNodeSet PreVisit;
2153 getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
2154
2155 ExplodedNodeSet PostVisit;
2156 for (const auto i : PreVisit)
2157 VisitCXXNewExpr(cast<CXXNewExpr>(S), i, PostVisit);
2158
2159 getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
2160 Bldr.addNodes(Dst);
2161 break;
2162 }
2163
2164 case Stmt::CXXDeleteExprClass: {
2165 Bldr.takeNodes(Pred);
2166 ExplodedNodeSet PreVisit;
2167 const auto *CDE = cast<CXXDeleteExpr>(S);
2168 getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
2169 ExplodedNodeSet PostVisit;
2170 getCheckerManager().runCheckersForPostStmt(PostVisit, PreVisit, S, *this);
2171
2172 for (const auto i : PostVisit)
2173 VisitCXXDeleteExpr(CDE, i, Dst);
2174
2175 Bldr.addNodes(Dst);
2176 break;
2177 }
2178 // FIXME: ChooseExpr is really a constant. We need to fix
2179 // the CFG do not model them as explicit control-flow.
2180
2181 case Stmt::ChooseExprClass: { // __builtin_choose_expr
2182 Bldr.takeNodes(Pred);
2183 const auto *C = cast<ChooseExpr>(S);
2184 VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
2185 Bldr.addNodes(Dst);
2186 break;
2187 }
2188
2189 case Stmt::CompoundAssignOperatorClass:
2190 Bldr.takeNodes(Pred);
2191 VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
2192 Bldr.addNodes(Dst);
2193 break;
2194
2195 case Stmt::CompoundLiteralExprClass:
2196 Bldr.takeNodes(Pred);
2197 VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
2198 Bldr.addNodes(Dst);
2199 break;
2200
2201 case Stmt::BinaryConditionalOperatorClass:
2202 case Stmt::ConditionalOperatorClass: { // '?' operator
2203 Bldr.takeNodes(Pred);
2204 const auto *C = cast<AbstractConditionalOperator>(S);
2205 VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
2206 Bldr.addNodes(Dst);
2207 break;
2208 }
2209
2210 case Stmt::CXXThisExprClass:
2211 Bldr.takeNodes(Pred);
2212 VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
2213 Bldr.addNodes(Dst);
2214 break;
2215
2216 case Stmt::DeclRefExprClass: {
2217 Bldr.takeNodes(Pred);
2218 const auto *DE = cast<DeclRefExpr>(S);
2219 VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
2220 Bldr.addNodes(Dst);
2221 break;
2222 }
2223
2224 case Stmt::DeclStmtClass:
2225 Bldr.takeNodes(Pred);
2226 VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
2227 Bldr.addNodes(Dst);
2228 break;
2229
2230 case Stmt::ImplicitCastExprClass:
2231 case Stmt::CStyleCastExprClass:
2232 case Stmt::CXXStaticCastExprClass:
2233 case Stmt::CXXDynamicCastExprClass:
2234 case Stmt::CXXReinterpretCastExprClass:
2235 case Stmt::CXXConstCastExprClass:
2236 case Stmt::CXXFunctionalCastExprClass:
2237 case Stmt::BuiltinBitCastExprClass:
2238 case Stmt::ObjCBridgedCastExprClass:
2239 case Stmt::CXXAddrspaceCastExprClass: {
2240 Bldr.takeNodes(Pred);
2241 const auto *C = cast<CastExpr>(S);
2242 ExplodedNodeSet dstExpr;
2243 VisitCast(C, C->getSubExpr(), Pred, dstExpr);
2244
2245 // Handle the postvisit checks.
2246 getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
2247 Bldr.addNodes(Dst);
2248 break;
2249 }
2250
2251 case Expr::MaterializeTemporaryExprClass: {
2252 Bldr.takeNodes(Pred);
2253 const auto *MTE = cast<MaterializeTemporaryExpr>(S);
2254 ExplodedNodeSet dstPrevisit;
2255 getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, MTE, *this);
2256 ExplodedNodeSet dstExpr;
2257 for (const auto i : dstPrevisit)
2258 CreateCXXTemporaryObject(MTE, i, dstExpr);
2259 getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, MTE, *this);
2260 Bldr.addNodes(Dst);
2261 break;
2262 }
2263
2264 case Stmt::InitListExprClass:
2265 Bldr.takeNodes(Pred);
2266 VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
2267 Bldr.addNodes(Dst);
2268 break;
2269
2270 case Stmt::MemberExprClass:
2271 Bldr.takeNodes(Pred);
2272 VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
2273 Bldr.addNodes(Dst);
2274 break;
2275
2276 case Stmt::AtomicExprClass:
2277 Bldr.takeNodes(Pred);
2278 VisitAtomicExpr(cast<AtomicExpr>(S), Pred, Dst);
2279 Bldr.addNodes(Dst);
2280 break;
2281
2282 case Stmt::ObjCIvarRefExprClass:
2283 Bldr.takeNodes(Pred);
2284 VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
2285 Bldr.addNodes(Dst);
2286 break;
2287
2288 case Stmt::ObjCForCollectionStmtClass:
2289 Bldr.takeNodes(Pred);
2290 VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
2291 Bldr.addNodes(Dst);
2292 break;
2293
2294 case Stmt::ObjCMessageExprClass:
2295 Bldr.takeNodes(Pred);
2296 VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
2297 Bldr.addNodes(Dst);
2298 break;
2299
2300 case Stmt::ObjCAtThrowStmtClass:
2301 case Stmt::CXXThrowExprClass:
2302 // FIXME: This is not complete. We basically treat @throw as
2303 // an abort.
2304 Bldr.generateSink(S, Pred, Pred->getState());
2305 break;
2306
2307 case Stmt::ReturnStmtClass:
2308 Bldr.takeNodes(Pred);
2309 VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
2310 Bldr.addNodes(Dst);
2311 break;
2312
2313 case Stmt::OffsetOfExprClass: {
2314 Bldr.takeNodes(Pred);
2315 ExplodedNodeSet PreVisit;
2316 getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
2317
2318 ExplodedNodeSet PostVisit;
2319 for (const auto Node : PreVisit)
2320 VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Node, PostVisit);
2321
2322 getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
2323 Bldr.addNodes(Dst);
2324 break;
2325 }
2326
2327 case Stmt::UnaryExprOrTypeTraitExprClass:
2328 Bldr.takeNodes(Pred);
2329 VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
2330 Pred, Dst);
2331 Bldr.addNodes(Dst);
2332 break;
2333
2334 case Stmt::StmtExprClass: {
2335 const auto *SE = cast<StmtExpr>(S);
2336
2337 if (SE->getSubStmt()->body_empty()) {
2338 // Empty statement expression.
2339 assert(SE->getType() == getContext().VoidTy
2340 && "Empty statement expression must have void type.");
2341 break;
2342 }
2343
2344 if (const auto *LastExpr =
2345 dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
2346 ProgramStateRef state = Pred->getState();
2347 Bldr.generateNode(SE, Pred,
2348 state->BindExpr(SE, Pred->getLocationContext(),
2349 state->getSVal(LastExpr,
2350 Pred->getLocationContext())));
2351 }
2352 break;
2353 }
2354
2355 case Stmt::UnaryOperatorClass: {
2356 Bldr.takeNodes(Pred);
2357 const auto *U = cast<UnaryOperator>(S);
2358 if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
2359 ExplodedNodeSet Tmp;
2360 VisitUnaryOperator(U, Pred, Tmp);
2361 evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
2362 }
2363 else
2364 VisitUnaryOperator(U, Pred, Dst);
2365 Bldr.addNodes(Dst);
2366 break;
2367 }
2368
2369 case Stmt::PseudoObjectExprClass: {
2370 Bldr.takeNodes(Pred);
2371 ProgramStateRef state = Pred->getState();
2372 const auto *PE = cast<PseudoObjectExpr>(S);
2373 if (const Expr *Result = PE->getResultExpr()) {
2374 SVal V = state->getSVal(Result, Pred->getLocationContext());
2375 Bldr.generateNode(S, Pred,
2376 state->BindExpr(S, Pred->getLocationContext(), V));
2377 }
2378 else
2379 Bldr.generateNode(S, Pred,
2380 state->BindExpr(S, Pred->getLocationContext(),
2381 UnknownVal()));
2382
2383 Bldr.addNodes(Dst);
2384 break;
2385 }
2386
2387 case Expr::ObjCIndirectCopyRestoreExprClass: {
2388 // ObjCIndirectCopyRestoreExpr implies passing a temporary for
2389 // correctness of lifetime management. Due to limited analysis
2390 // of ARC, this is implemented as direct arg passing.
2391 Bldr.takeNodes(Pred);
2392 ProgramStateRef state = Pred->getState();
2393 const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(S);
2394 const Expr *E = OIE->getSubExpr();
2395 SVal V = state->getSVal(E, Pred->getLocationContext());
2396 Bldr.generateNode(S, Pred,
2397 state->BindExpr(S, Pred->getLocationContext(), V));
2398 Bldr.addNodes(Dst);
2399 break;
2400 }
2401 }
2402 }
2403
replayWithoutInlining(ExplodedNode * N,const LocationContext * CalleeLC)2404 bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
2405 const LocationContext *CalleeLC) {
2406 const StackFrameContext *CalleeSF = CalleeLC->getStackFrame();
2407 const StackFrameContext *CallerSF = CalleeSF->getParent()->getStackFrame();
2408 assert(CalleeSF && CallerSF);
2409 ExplodedNode *BeforeProcessingCall = nullptr;
2410 const Stmt *CE = CalleeSF->getCallSite();
2411
2412 // Find the first node before we started processing the call expression.
2413 while (N) {
2414 ProgramPoint L = N->getLocation();
2415 BeforeProcessingCall = N;
2416 N = N->pred_empty() ? nullptr : *(N->pred_begin());
2417
2418 // Skip the nodes corresponding to the inlined code.
2419 if (L.getStackFrame() != CallerSF)
2420 continue;
2421 // We reached the caller. Find the node right before we started
2422 // processing the call.
2423 if (L.isPurgeKind())
2424 continue;
2425 if (L.getAs<PreImplicitCall>())
2426 continue;
2427 if (L.getAs<CallEnter>())
2428 continue;
2429 if (std::optional<StmtPoint> SP = L.getAs<StmtPoint>())
2430 if (SP->getStmt() == CE)
2431 continue;
2432 break;
2433 }
2434
2435 if (!BeforeProcessingCall)
2436 return false;
2437
2438 // TODO: Clean up the unneeded nodes.
2439
2440 // Build an Epsilon node from which we will restart the analyzes.
2441 // Note that CE is permitted to be NULL!
2442 static SimpleProgramPointTag PT("ExprEngine", "Replay without inlining");
2443 ProgramPoint NewNodeLoc = EpsilonPoint(
2444 BeforeProcessingCall->getLocationContext(), CE, nullptr, &PT);
2445 // Add the special flag to GDM to signal retrying with no inlining.
2446 // Note, changing the state ensures that we are not going to cache out.
2447 ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
2448 NewNodeState =
2449 NewNodeState->set<ReplayWithoutInlining>(const_cast<Stmt *>(CE));
2450
2451 // Make the new node a successor of BeforeProcessingCall.
2452 bool IsNew = false;
2453 ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew);
2454 // We cached out at this point. Caching out is common due to us backtracking
2455 // from the inlined function, which might spawn several paths.
2456 if (!IsNew)
2457 return true;
2458
2459 NewNode->addPredecessor(BeforeProcessingCall, G);
2460
2461 // Add the new node to the work list.
2462 Engine.enqueueStmtNode(NewNode, CalleeSF->getCallSiteBlock(),
2463 CalleeSF->getIndex());
2464 NumTimesRetriedWithoutInlining++;
2465 return true;
2466 }
2467
2468 /// Block entrance. (Update counters).
processCFGBlockEntrance(const BlockEdge & L,NodeBuilderWithSinks & nodeBuilder,ExplodedNode * Pred)2469 void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
2470 NodeBuilderWithSinks &nodeBuilder,
2471 ExplodedNode *Pred) {
2472 PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
2473 // If we reach a loop which has a known bound (and meets
2474 // other constraints) then consider completely unrolling it.
2475 if(AMgr.options.ShouldUnrollLoops) {
2476 unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
2477 const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt();
2478 if (Term) {
2479 ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
2480 Pred, maxBlockVisitOnPath);
2481 if (NewState != Pred->getState()) {
2482 ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
2483 if (!UpdatedNode)
2484 return;
2485 Pred = UpdatedNode;
2486 }
2487 }
2488 // Is we are inside an unrolled loop then no need the check the counters.
2489 if(isUnrolledState(Pred->getState()))
2490 return;
2491 }
2492
2493 // If this block is terminated by a loop and it has already been visited the
2494 // maximum number of times, widen the loop.
2495 unsigned int BlockCount = nodeBuilder.getContext().blockCount();
2496 if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 &&
2497 AMgr.options.ShouldWidenLoops) {
2498 const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt();
2499 if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt>(Term))
2500 return;
2501 // Widen.
2502 const LocationContext *LCtx = Pred->getLocationContext();
2503 ProgramStateRef WidenedState =
2504 getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term);
2505 nodeBuilder.generateNode(WidenedState, Pred);
2506 return;
2507 }
2508
2509 // FIXME: Refactor this into a checker.
2510 if (BlockCount >= AMgr.options.maxBlockVisitOnPath) {
2511 static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded");
2512 const ExplodedNode *Sink =
2513 nodeBuilder.generateSink(Pred->getState(), Pred, &tag);
2514
2515 // Check if we stopped at the top level function or not.
2516 // Root node should have the location context of the top most function.
2517 const LocationContext *CalleeLC = Pred->getLocation().getLocationContext();
2518 const LocationContext *CalleeSF = CalleeLC->getStackFrame();
2519 const LocationContext *RootLC =
2520 (*G.roots_begin())->getLocation().getLocationContext();
2521 if (RootLC->getStackFrame() != CalleeSF) {
2522 Engine.FunctionSummaries->markReachedMaxBlockCount(CalleeSF->getDecl());
2523
2524 // Re-run the call evaluation without inlining it, by storing the
2525 // no-inlining policy in the state and enqueuing the new work item on
2526 // the list. Replay should almost never fail. Use the stats to catch it
2527 // if it does.
2528 if ((!AMgr.options.NoRetryExhausted &&
2529 replayWithoutInlining(Pred, CalleeLC)))
2530 return;
2531 NumMaxBlockCountReachedInInlined++;
2532 } else
2533 NumMaxBlockCountReached++;
2534
2535 // Make sink nodes as exhausted(for stats) only if retry failed.
2536 Engine.blocksExhausted.push_back(std::make_pair(L, Sink));
2537 }
2538 }
2539
2540 //===----------------------------------------------------------------------===//
2541 // Branch processing.
2542 //===----------------------------------------------------------------------===//
2543
2544 /// RecoverCastedSymbol - A helper function for ProcessBranch that is used
2545 /// to try to recover some path-sensitivity for casts of symbolic
2546 /// integers that promote their values (which are currently not tracked well).
2547 /// This function returns the SVal bound to Condition->IgnoreCasts if all the
2548 // cast(s) did was sign-extend the original value.
RecoverCastedSymbol(ProgramStateRef state,const Stmt * Condition,const LocationContext * LCtx,ASTContext & Ctx)2549 static SVal RecoverCastedSymbol(ProgramStateRef state,
2550 const Stmt *Condition,
2551 const LocationContext *LCtx,
2552 ASTContext &Ctx) {
2553
2554 const auto *Ex = dyn_cast<Expr>(Condition);
2555 if (!Ex)
2556 return UnknownVal();
2557
2558 uint64_t bits = 0;
2559 bool bitsInit = false;
2560
2561 while (const auto *CE = dyn_cast<CastExpr>(Ex)) {
2562 QualType T = CE->getType();
2563
2564 if (!T->isIntegralOrEnumerationType())
2565 return UnknownVal();
2566
2567 uint64_t newBits = Ctx.getTypeSize(T);
2568 if (!bitsInit || newBits < bits) {
2569 bitsInit = true;
2570 bits = newBits;
2571 }
2572
2573 Ex = CE->getSubExpr();
2574 }
2575
2576 // We reached a non-cast. Is it a symbolic value?
2577 QualType T = Ex->getType();
2578
2579 if (!bitsInit || !T->isIntegralOrEnumerationType() ||
2580 Ctx.getTypeSize(T) > bits)
2581 return UnknownVal();
2582
2583 return state->getSVal(Ex, LCtx);
2584 }
2585
2586 #ifndef NDEBUG
getRightmostLeaf(const Stmt * Condition)2587 static const Stmt *getRightmostLeaf(const Stmt *Condition) {
2588 while (Condition) {
2589 const auto *BO = dyn_cast<BinaryOperator>(Condition);
2590 if (!BO || !BO->isLogicalOp()) {
2591 return Condition;
2592 }
2593 Condition = BO->getRHS()->IgnoreParens();
2594 }
2595 return nullptr;
2596 }
2597 #endif
2598
2599 // Returns the condition the branch at the end of 'B' depends on and whose value
2600 // has been evaluated within 'B'.
2601 // In most cases, the terminator condition of 'B' will be evaluated fully in
2602 // the last statement of 'B'; in those cases, the resolved condition is the
2603 // given 'Condition'.
2604 // If the condition of the branch is a logical binary operator tree, the CFG is
2605 // optimized: in that case, we know that the expression formed by all but the
2606 // rightmost leaf of the logical binary operator tree must be true, and thus
2607 // the branch condition is at this point equivalent to the truth value of that
2608 // rightmost leaf; the CFG block thus only evaluates this rightmost leaf
2609 // expression in its final statement. As the full condition in that case was
2610 // not evaluated, and is thus not in the SVal cache, we need to use that leaf
2611 // expression to evaluate the truth value of the condition in the current state
2612 // space.
ResolveCondition(const Stmt * Condition,const CFGBlock * B)2613 static const Stmt *ResolveCondition(const Stmt *Condition,
2614 const CFGBlock *B) {
2615 if (const auto *Ex = dyn_cast<Expr>(Condition))
2616 Condition = Ex->IgnoreParens();
2617
2618 const auto *BO = dyn_cast<BinaryOperator>(Condition);
2619 if (!BO || !BO->isLogicalOp())
2620 return Condition;
2621
2622 assert(B->getTerminator().isStmtBranch() &&
2623 "Other kinds of branches are handled separately!");
2624
2625 // For logical operations, we still have the case where some branches
2626 // use the traditional "merge" approach and others sink the branch
2627 // directly into the basic blocks representing the logical operation.
2628 // We need to distinguish between those two cases here.
2629
2630 // The invariants are still shifting, but it is possible that the
2631 // last element in a CFGBlock is not a CFGStmt. Look for the last
2632 // CFGStmt as the value of the condition.
2633 CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
2634 for (; I != E; ++I) {
2635 CFGElement Elem = *I;
2636 std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
2637 if (!CS)
2638 continue;
2639 const Stmt *LastStmt = CS->getStmt();
2640 assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition));
2641 return LastStmt;
2642 }
2643 llvm_unreachable("could not resolve condition");
2644 }
2645
2646 using ObjCForLctxPair =
2647 std::pair<const ObjCForCollectionStmt *, const LocationContext *>;
2648
REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations,ObjCForLctxPair,bool)2649 REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool)
2650
2651 ProgramStateRef ExprEngine::setWhetherHasMoreIteration(
2652 ProgramStateRef State, const ObjCForCollectionStmt *O,
2653 const LocationContext *LC, bool HasMoreIteraton) {
2654 assert(!State->contains<ObjCForHasMoreIterations>({O, LC}));
2655 return State->set<ObjCForHasMoreIterations>({O, LC}, HasMoreIteraton);
2656 }
2657
2658 ProgramStateRef
removeIterationState(ProgramStateRef State,const ObjCForCollectionStmt * O,const LocationContext * LC)2659 ExprEngine::removeIterationState(ProgramStateRef State,
2660 const ObjCForCollectionStmt *O,
2661 const LocationContext *LC) {
2662 assert(State->contains<ObjCForHasMoreIterations>({O, LC}));
2663 return State->remove<ObjCForHasMoreIterations>({O, LC});
2664 }
2665
hasMoreIteration(ProgramStateRef State,const ObjCForCollectionStmt * O,const LocationContext * LC)2666 bool ExprEngine::hasMoreIteration(ProgramStateRef State,
2667 const ObjCForCollectionStmt *O,
2668 const LocationContext *LC) {
2669 assert(State->contains<ObjCForHasMoreIterations>({O, LC}));
2670 return *State->get<ObjCForHasMoreIterations>({O, LC});
2671 }
2672
2673 /// Split the state on whether there are any more iterations left for this loop.
2674 /// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when
2675 /// the acquisition of the loop condition value failed.
2676 static std::optional<std::pair<ProgramStateRef, ProgramStateRef>>
assumeCondition(const Stmt * Condition,ExplodedNode * N)2677 assumeCondition(const Stmt *Condition, ExplodedNode *N) {
2678 ProgramStateRef State = N->getState();
2679 if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Condition)) {
2680 bool HasMoreIteraton =
2681 ExprEngine::hasMoreIteration(State, ObjCFor, N->getLocationContext());
2682 // Checkers have already ran on branch conditions, so the current
2683 // information as to whether the loop has more iteration becomes outdated
2684 // after this point.
2685 State = ExprEngine::removeIterationState(State, ObjCFor,
2686 N->getLocationContext());
2687 if (HasMoreIteraton)
2688 return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr};
2689 else
2690 return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State};
2691 }
2692 SVal X = State->getSVal(Condition, N->getLocationContext());
2693
2694 if (X.isUnknownOrUndef()) {
2695 // Give it a chance to recover from unknown.
2696 if (const auto *Ex = dyn_cast<Expr>(Condition)) {
2697 if (Ex->getType()->isIntegralOrEnumerationType()) {
2698 // Try to recover some path-sensitivity. Right now casts of symbolic
2699 // integers that promote their values are currently not tracked well.
2700 // If 'Condition' is such an expression, try and recover the
2701 // underlying value and use that instead.
2702 SVal recovered =
2703 RecoverCastedSymbol(State, Condition, N->getLocationContext(),
2704 N->getState()->getStateManager().getContext());
2705
2706 if (!recovered.isUnknown()) {
2707 X = recovered;
2708 }
2709 }
2710 }
2711 }
2712
2713 // If the condition is still unknown, give up.
2714 if (X.isUnknownOrUndef())
2715 return std::nullopt;
2716
2717 DefinedSVal V = X.castAs<DefinedSVal>();
2718
2719 ProgramStateRef StTrue, StFalse;
2720 return State->assume(V);
2721 }
2722
processBranch(const Stmt * Condition,NodeBuilderContext & BldCtx,ExplodedNode * Pred,ExplodedNodeSet & Dst,const CFGBlock * DstT,const CFGBlock * DstF)2723 void ExprEngine::processBranch(const Stmt *Condition,
2724 NodeBuilderContext& BldCtx,
2725 ExplodedNode *Pred,
2726 ExplodedNodeSet &Dst,
2727 const CFGBlock *DstT,
2728 const CFGBlock *DstF) {
2729 assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
2730 "CXXBindTemporaryExprs are handled by processBindTemporary.");
2731 const LocationContext *LCtx = Pred->getLocationContext();
2732 PrettyStackTraceLocationContext StackCrashInfo(LCtx);
2733 currBldrCtx = &BldCtx;
2734
2735 // Check for NULL conditions; e.g. "for(;;)"
2736 if (!Condition) {
2737 BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
2738 NullCondBldr.markInfeasible(false);
2739 NullCondBldr.generateNode(Pred->getState(), true, Pred);
2740 return;
2741 }
2742
2743 if (const auto *Ex = dyn_cast<Expr>(Condition))
2744 Condition = Ex->IgnoreParens();
2745
2746 Condition = ResolveCondition(Condition, BldCtx.getBlock());
2747 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
2748 Condition->getBeginLoc(),
2749 "Error evaluating branch");
2750
2751 ExplodedNodeSet CheckersOutSet;
2752 getCheckerManager().runCheckersForBranchCondition(Condition, CheckersOutSet,
2753 Pred, *this);
2754 // We generated only sinks.
2755 if (CheckersOutSet.empty())
2756 return;
2757
2758 BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF);
2759 for (ExplodedNode *PredN : CheckersOutSet) {
2760 if (PredN->isSink())
2761 continue;
2762
2763 ProgramStateRef PrevState = PredN->getState();
2764
2765 ProgramStateRef StTrue, StFalse;
2766 if (const auto KnownCondValueAssumption = assumeCondition(Condition, PredN))
2767 std::tie(StTrue, StFalse) = *KnownCondValueAssumption;
2768 else {
2769 assert(!isa<ObjCForCollectionStmt>(Condition));
2770 builder.generateNode(PrevState, true, PredN);
2771 builder.generateNode(PrevState, false, PredN);
2772 continue;
2773 }
2774 if (StTrue && StFalse)
2775 assert(!isa<ObjCForCollectionStmt>(Condition));
2776
2777 // Process the true branch.
2778 if (builder.isFeasible(true)) {
2779 if (StTrue)
2780 builder.generateNode(StTrue, true, PredN);
2781 else
2782 builder.markInfeasible(true);
2783 }
2784
2785 // Process the false branch.
2786 if (builder.isFeasible(false)) {
2787 if (StFalse)
2788 builder.generateNode(StFalse, false, PredN);
2789 else
2790 builder.markInfeasible(false);
2791 }
2792 }
2793 currBldrCtx = nullptr;
2794 }
2795
2796 /// The GDM component containing the set of global variables which have been
2797 /// previously initialized with explicit initializers.
REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,llvm::ImmutableSet<const VarDecl * >)2798 REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
2799 llvm::ImmutableSet<const VarDecl *>)
2800
2801 void ExprEngine::processStaticInitializer(const DeclStmt *DS,
2802 NodeBuilderContext &BuilderCtx,
2803 ExplodedNode *Pred,
2804 ExplodedNodeSet &Dst,
2805 const CFGBlock *DstT,
2806 const CFGBlock *DstF) {
2807 PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
2808 currBldrCtx = &BuilderCtx;
2809
2810 const auto *VD = cast<VarDecl>(DS->getSingleDecl());
2811 ProgramStateRef state = Pred->getState();
2812 bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
2813 BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF);
2814
2815 if (!initHasRun) {
2816 state = state->add<InitializedGlobalsSet>(VD);
2817 }
2818
2819 builder.generateNode(state, initHasRun, Pred);
2820 builder.markInfeasible(!initHasRun);
2821
2822 currBldrCtx = nullptr;
2823 }
2824
2825 /// processIndirectGoto - Called by CoreEngine. Used to generate successor
2826 /// nodes by processing the 'effects' of a computed goto jump.
processIndirectGoto(IndirectGotoNodeBuilder & builder)2827 void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
2828 ProgramStateRef state = builder.getState();
2829 SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext());
2830
2831 // Three possibilities:
2832 //
2833 // (1) We know the computed label.
2834 // (2) The label is NULL (or some other constant), or Undefined.
2835 // (3) We have no clue about the label. Dispatch to all targets.
2836 //
2837
2838 using iterator = IndirectGotoNodeBuilder::iterator;
2839
2840 if (std::optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
2841 const LabelDecl *L = LV->getLabel();
2842
2843 for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
2844 if (I.getLabel() == L) {
2845 builder.generateNode(I, state);
2846 return;
2847 }
2848 }
2849
2850 llvm_unreachable("No block with label.");
2851 }
2852
2853 if (isa<UndefinedVal, loc::ConcreteInt>(V)) {
2854 // Dispatch to the first target and mark it as a sink.
2855 //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
2856 // FIXME: add checker visit.
2857 // UndefBranches.insert(N);
2858 return;
2859 }
2860
2861 // This is really a catch-all. We don't support symbolics yet.
2862 // FIXME: Implement dispatch for symbolic pointers.
2863
2864 for (iterator I = builder.begin(), E = builder.end(); I != E; ++I)
2865 builder.generateNode(I, state);
2866 }
2867
processBeginOfFunction(NodeBuilderContext & BC,ExplodedNode * Pred,ExplodedNodeSet & Dst,const BlockEdge & L)2868 void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC,
2869 ExplodedNode *Pred,
2870 ExplodedNodeSet &Dst,
2871 const BlockEdge &L) {
2872 SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
2873 getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, *this);
2874 }
2875
2876 /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
2877 /// nodes when the control reaches the end of a function.
processEndOfFunction(NodeBuilderContext & BC,ExplodedNode * Pred,const ReturnStmt * RS)2878 void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
2879 ExplodedNode *Pred,
2880 const ReturnStmt *RS) {
2881 ProgramStateRef State = Pred->getState();
2882
2883 if (!Pred->getStackFrame()->inTopFrame())
2884 State = finishArgumentConstruction(
2885 State, *getStateManager().getCallEventManager().getCaller(
2886 Pred->getStackFrame(), Pred->getState()));
2887
2888 // FIXME: We currently cannot assert that temporaries are clear, because
2889 // lifetime extended temporaries are not always modelled correctly. In some
2890 // cases when we materialize the temporary, we do
2891 // createTemporaryRegionIfNeeded(), and the region changes, and also the
2892 // respective destructor becomes automatic from temporary. So for now clean up
2893 // the state manually before asserting. Ideally, this braced block of code
2894 // should go away.
2895 {
2896 const LocationContext *FromLC = Pred->getLocationContext();
2897 const LocationContext *ToLC = FromLC->getStackFrame()->getParent();
2898 const LocationContext *LC = FromLC;
2899 while (LC != ToLC) {
2900 assert(LC && "ToLC must be a parent of FromLC!");
2901 for (auto I : State->get<ObjectsUnderConstruction>())
2902 if (I.first.getLocationContext() == LC) {
2903 // The comment above only pardons us for not cleaning up a
2904 // temporary destructor. If any other statements are found here,
2905 // it must be a separate problem.
2906 assert(I.first.getItem().getKind() ==
2907 ConstructionContextItem::TemporaryDestructorKind ||
2908 I.first.getItem().getKind() ==
2909 ConstructionContextItem::ElidedDestructorKind);
2910 State = State->remove<ObjectsUnderConstruction>(I.first);
2911 }
2912 LC = LC->getParent();
2913 }
2914 }
2915
2916 // Perform the transition with cleanups.
2917 if (State != Pred->getState()) {
2918 ExplodedNodeSet PostCleanup;
2919 NodeBuilder Bldr(Pred, PostCleanup, BC);
2920 Pred = Bldr.generateNode(Pred->getLocation(), State, Pred);
2921 if (!Pred) {
2922 // The node with clean temporaries already exists. We might have reached
2923 // it on a path on which we initialize different temporaries.
2924 return;
2925 }
2926 }
2927
2928 assert(areAllObjectsFullyConstructed(Pred->getState(),
2929 Pred->getLocationContext(),
2930 Pred->getStackFrame()->getParent()));
2931
2932 PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
2933
2934 ExplodedNodeSet Dst;
2935 if (Pred->getLocationContext()->inTopFrame()) {
2936 // Remove dead symbols.
2937 ExplodedNodeSet AfterRemovedDead;
2938 removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead);
2939
2940 // Notify checkers.
2941 for (const auto I : AfterRemovedDead)
2942 getCheckerManager().runCheckersForEndFunction(BC, Dst, I, *this, RS);
2943 } else {
2944 getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this, RS);
2945 }
2946
2947 Engine.enqueueEndOfFunction(Dst, RS);
2948 }
2949
2950 /// ProcessSwitch - Called by CoreEngine. Used to generate successor
2951 /// nodes by processing the 'effects' of a switch statement.
processSwitch(SwitchNodeBuilder & builder)2952 void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
2953 using iterator = SwitchNodeBuilder::iterator;
2954
2955 ProgramStateRef state = builder.getState();
2956 const Expr *CondE = builder.getCondition();
2957 SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext());
2958
2959 if (CondV_untested.isUndef()) {
2960 //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
2961 // FIXME: add checker
2962 //UndefBranches.insert(N);
2963
2964 return;
2965 }
2966 DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>();
2967
2968 ProgramStateRef DefaultSt = state;
2969
2970 iterator I = builder.begin(), EI = builder.end();
2971 bool defaultIsFeasible = I == EI;
2972
2973 for ( ; I != EI; ++I) {
2974 // Successor may be pruned out during CFG construction.
2975 if (!I.getBlock())
2976 continue;
2977
2978 const CaseStmt *Case = I.getCase();
2979
2980 // Evaluate the LHS of the case value.
2981 llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
2982 assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType()));
2983
2984 // Get the RHS of the case, if it exists.
2985 llvm::APSInt V2;
2986 if (const Expr *E = Case->getRHS())
2987 V2 = E->EvaluateKnownConstInt(getContext());
2988 else
2989 V2 = V1;
2990
2991 ProgramStateRef StateCase;
2992 if (std::optional<NonLoc> NL = CondV.getAs<NonLoc>())
2993 std::tie(StateCase, DefaultSt) =
2994 DefaultSt->assumeInclusiveRange(*NL, V1, V2);
2995 else // UnknownVal
2996 StateCase = DefaultSt;
2997
2998 if (StateCase)
2999 builder.generateCaseStmtNode(I, StateCase);
3000
3001 // Now "assume" that the case doesn't match. Add this state
3002 // to the default state (if it is feasible).
3003 if (DefaultSt)
3004 defaultIsFeasible = true;
3005 else {
3006 defaultIsFeasible = false;
3007 break;
3008 }
3009 }
3010
3011 if (!defaultIsFeasible)
3012 return;
3013
3014 // If we have switch(enum value), the default branch is not
3015 // feasible if all of the enum constants not covered by 'case:' statements
3016 // are not feasible values for the switch condition.
3017 //
3018 // Note that this isn't as accurate as it could be. Even if there isn't
3019 // a case for a particular enum value as long as that enum value isn't
3020 // feasible then it shouldn't be considered for making 'default:' reachable.
3021 const SwitchStmt *SS = builder.getSwitch();
3022 const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts();
3023 if (CondExpr->getType()->getAs<EnumType>()) {
3024 if (SS->isAllEnumCasesCovered())
3025 return;
3026 }
3027
3028 builder.generateDefaultCaseNode(DefaultSt);
3029 }
3030
3031 //===----------------------------------------------------------------------===//
3032 // Transfer functions: Loads and stores.
3033 //===----------------------------------------------------------------------===//
3034
VisitCommonDeclRefExpr(const Expr * Ex,const NamedDecl * D,ExplodedNode * Pred,ExplodedNodeSet & Dst)3035 void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
3036 ExplodedNode *Pred,
3037 ExplodedNodeSet &Dst) {
3038 StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
3039
3040 ProgramStateRef state = Pred->getState();
3041 const LocationContext *LCtx = Pred->getLocationContext();
3042
3043 if (const auto *VD = dyn_cast<VarDecl>(D)) {
3044 // C permits "extern void v", and if you cast the address to a valid type,
3045 // you can even do things with it. We simply pretend
3046 assert(Ex->isGLValue() || VD->getType()->isVoidType());
3047 const LocationContext *LocCtxt = Pred->getLocationContext();
3048 const Decl *D = LocCtxt->getDecl();
3049 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
3050 const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
3051 std::optional<std::pair<SVal, QualType>> VInfo;
3052
3053 if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
3054 DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
3055 MD->getParent()->isLambda()) {
3056 // Lookup the field of the lambda.
3057 const CXXRecordDecl *CXXRec = MD->getParent();
3058 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
3059 FieldDecl *LambdaThisCaptureField;
3060 CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
3061
3062 // Sema follows a sequence of complex rules to determine whether the
3063 // variable should be captured.
3064 if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
3065 Loc CXXThis =
3066 svalBuilder.getCXXThis(MD, LocCtxt->getStackFrame());
3067 SVal CXXThisVal = state->getSVal(CXXThis);
3068 VInfo = std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType());
3069 }
3070 }
3071
3072 if (!VInfo)
3073 VInfo = std::make_pair(state->getLValue(VD, LocCtxt), VD->getType());
3074
3075 SVal V = VInfo->first;
3076 bool IsReference = VInfo->second->isReferenceType();
3077
3078 // For references, the 'lvalue' is the pointer address stored in the
3079 // reference region.
3080 if (IsReference) {
3081 if (const MemRegion *R = V.getAsRegion())
3082 V = state->getSVal(R);
3083 else
3084 V = UnknownVal();
3085 }
3086
3087 Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
3088 ProgramPoint::PostLValueKind);
3089 return;
3090 }
3091 if (const auto *ED = dyn_cast<EnumConstantDecl>(D)) {
3092 assert(!Ex->isGLValue());
3093 SVal V = svalBuilder.makeIntVal(ED->getInitVal());
3094 Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V));
3095 return;
3096 }
3097 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3098 SVal V = svalBuilder.getFunctionPointer(FD);
3099 Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
3100 ProgramPoint::PostLValueKind);
3101 return;
3102 }
3103 if (isa<FieldDecl, IndirectFieldDecl>(D)) {
3104 // Delegate all work related to pointer to members to the surrounding
3105 // operator&.
3106 return;
3107 }
3108 if (const auto *BD = dyn_cast<BindingDecl>(D)) {
3109 const auto *DD = cast<DecompositionDecl>(BD->getDecomposedDecl());
3110
3111 SVal Base = state->getLValue(DD, LCtx);
3112 if (DD->getType()->isReferenceType()) {
3113 if (const MemRegion *R = Base.getAsRegion())
3114 Base = state->getSVal(R);
3115 else
3116 Base = UnknownVal();
3117 }
3118
3119 SVal V = UnknownVal();
3120
3121 // Handle binding to data members
3122 if (const auto *ME = dyn_cast<MemberExpr>(BD->getBinding())) {
3123 const auto *Field = cast<FieldDecl>(ME->getMemberDecl());
3124 V = state->getLValue(Field, Base);
3125 }
3126 // Handle binding to arrays
3127 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BD->getBinding())) {
3128 SVal Idx = state->getSVal(ASE->getIdx(), LCtx);
3129
3130 // Note: the index of an element in a structured binding is automatically
3131 // created and it is a unique identifier of the specific element. Thus it
3132 // cannot be a value that varies at runtime.
3133 assert(Idx.isConstant() && "BindingDecl array index is not a constant!");
3134
3135 V = state->getLValue(BD->getType(), Idx, Base);
3136 }
3137 // Handle binding to tuple-like structures
3138 else if (const auto *HV = BD->getHoldingVar()) {
3139 V = state->getLValue(HV, LCtx);
3140
3141 if (HV->getType()->isReferenceType()) {
3142 if (const MemRegion *R = V.getAsRegion())
3143 V = state->getSVal(R);
3144 else
3145 V = UnknownVal();
3146 }
3147 } else
3148 llvm_unreachable("An unknown case of structured binding encountered!");
3149
3150 // In case of tuple-like types the references are already handled, so we
3151 // don't want to handle them again.
3152 if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
3153 if (const MemRegion *R = V.getAsRegion())
3154 V = state->getSVal(R);
3155 else
3156 V = UnknownVal();
3157 }
3158
3159 Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
3160 ProgramPoint::PostLValueKind);
3161
3162 return;
3163 }
3164
3165 if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) {
3166 // FIXME: We should meaningfully implement this.
3167 (void)TPO;
3168 return;
3169 }
3170
3171 llvm_unreachable("Support for this Decl not implemented.");
3172 }
3173
3174 /// VisitArrayInitLoopExpr - Transfer function for array init loop.
VisitArrayInitLoopExpr(const ArrayInitLoopExpr * Ex,ExplodedNode * Pred,ExplodedNodeSet & Dst)3175 void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
3176 ExplodedNode *Pred,
3177 ExplodedNodeSet &Dst) {
3178 ExplodedNodeSet CheckerPreStmt;
3179 getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, Ex, *this);
3180
3181 ExplodedNodeSet EvalSet;
3182 StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
3183
3184 const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
3185
3186 for (auto *Node : CheckerPreStmt) {
3187
3188 // The constructor visitior has already taken care of everything.
3189 if (isa<CXXConstructExpr>(Ex->getSubExpr()))
3190 break;
3191
3192 const LocationContext *LCtx = Node->getLocationContext();
3193 ProgramStateRef state = Node->getState();
3194
3195 SVal Base = UnknownVal();
3196
3197 // As in case of this expression the sub-expressions are not visited by any
3198 // other transfer functions, they are handled by matching their AST.
3199
3200 // Case of implicit copy or move ctor of object with array member
3201 //
3202 // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
3203 // environment.
3204 //
3205 // struct S {
3206 // int arr[2];
3207 // };
3208 //
3209 //
3210 // S a;
3211 // S b = a;
3212 //
3213 // The AST in case of a *copy constructor* looks like this:
3214 // ArrayInitLoopExpr
3215 // |-OpaqueValueExpr
3216 // | `-MemberExpr <-- match this
3217 // | `-DeclRefExpr
3218 // ` ...
3219 //
3220 //
3221 // S c;
3222 // S d = std::move(d);
3223 //
3224 // In case of a *move constructor* the resulting AST looks like:
3225 // ArrayInitLoopExpr
3226 // |-OpaqueValueExpr
3227 // | `-MemberExpr <-- match this first
3228 // | `-CXXStaticCastExpr <-- match this after
3229 // | `-DeclRefExpr
3230 // ` ...
3231 if (const auto *ME = dyn_cast<MemberExpr>(Arr)) {
3232 Expr *MEBase = ME->getBase();
3233
3234 // Move ctor
3235 if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(MEBase)) {
3236 MEBase = CXXSCE->getSubExpr();
3237 }
3238
3239 auto ObjDeclExpr = cast<DeclRefExpr>(MEBase);
3240 SVal Obj = state->getLValue(cast<VarDecl>(ObjDeclExpr->getDecl()), LCtx);
3241
3242 Base = state->getLValue(cast<FieldDecl>(ME->getMemberDecl()), Obj);
3243 }
3244
3245 // Case of lambda capture and decomposition declaration
3246 //
3247 // int arr[2];
3248 //
3249 // [arr]{ int a = arr[0]; }();
3250 // auto[a, b] = arr;
3251 //
3252 // In both of these cases the AST looks like the following:
3253 // ArrayInitLoopExpr
3254 // |-OpaqueValueExpr
3255 // | `-DeclRefExpr <-- match this
3256 // ` ...
3257 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arr))
3258 Base = state->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
3259
3260 // Create a lazy compound value to the original array
3261 if (const MemRegion *R = Base.getAsRegion())
3262 Base = state->getSVal(R);
3263 else
3264 Base = UnknownVal();
3265
3266 Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, Base));
3267 }
3268
3269 getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
3270 }
3271
3272 /// VisitArraySubscriptExpr - Transfer function for array accesses
VisitArraySubscriptExpr(const ArraySubscriptExpr * A,ExplodedNode * Pred,ExplodedNodeSet & Dst)3273 void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
3274 ExplodedNode *Pred,
3275 ExplodedNodeSet &Dst){
3276 const Expr *Base = A->getBase()->IgnoreParens();
3277 const Expr *Idx = A->getIdx()->IgnoreParens();
3278
3279 ExplodedNodeSet CheckerPreStmt;
3280 getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
3281
3282 ExplodedNodeSet EvalSet;
3283 StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
3284
3285 bool IsVectorType = A->getBase()->getType()->isVectorType();
3286
3287 // The "like" case is for situations where C standard prohibits the type to
3288 // be an lvalue, e.g. taking the address of a subscript of an expression of
3289 // type "void *".
3290 bool IsGLValueLike = A->isGLValue() ||
3291 (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
3292
3293 for (auto *Node : CheckerPreStmt) {
3294 const LocationContext *LCtx = Node->getLocationContext();
3295 ProgramStateRef state = Node->getState();
3296
3297 if (IsGLValueLike) {
3298 QualType T = A->getType();
3299
3300 // One of the forbidden LValue types! We still need to have sensible
3301 // symbolic locations to represent this stuff. Note that arithmetic on
3302 // void pointers is a GCC extension.
3303 if (T->isVoidType())
3304 T = getContext().CharTy;
3305
3306 SVal V = state->getLValue(T,
3307 state->getSVal(Idx, LCtx),
3308 state->getSVal(Base, LCtx));
3309 Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr,
3310 ProgramPoint::PostLValueKind);
3311 } else if (IsVectorType) {
3312 // FIXME: non-glvalue vector reads are not modelled.
3313 Bldr.generateNode(A, Node, state, nullptr);
3314 } else {
3315 llvm_unreachable("Array subscript should be an lValue when not \
3316 a vector and not a forbidden lvalue type");
3317 }
3318 }
3319
3320 getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
3321 }
3322
3323 /// VisitMemberExpr - Transfer function for member expressions.
VisitMemberExpr(const MemberExpr * M,ExplodedNode * Pred,ExplodedNodeSet & Dst)3324 void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
3325 ExplodedNodeSet &Dst) {
3326 // FIXME: Prechecks eventually go in ::Visit().
3327 ExplodedNodeSet CheckedSet;
3328 getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this);
3329
3330 ExplodedNodeSet EvalSet;
3331 ValueDecl *Member = M->getMemberDecl();
3332
3333 // Handle static member variables and enum constants accessed via
3334 // member syntax.
3335 if (isa<VarDecl, EnumConstantDecl>(Member)) {
3336 for (const auto I : CheckedSet)
3337 VisitCommonDeclRefExpr(M, Member, I, EvalSet);
3338 } else {
3339 StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
3340 ExplodedNodeSet Tmp;
3341
3342 for (const auto I : CheckedSet) {
3343 ProgramStateRef state = I->getState();
3344 const LocationContext *LCtx = I->getLocationContext();
3345 Expr *BaseExpr = M->getBase();
3346
3347 // Handle C++ method calls.
3348 if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) {
3349 if (MD->isInstance())
3350 state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
3351
3352 SVal MDVal = svalBuilder.getFunctionPointer(MD);
3353 state = state->BindExpr(M, LCtx, MDVal);
3354
3355 Bldr.generateNode(M, I, state);
3356 continue;
3357 }
3358
3359 // Handle regular struct fields / member variables.
3360 const SubRegion *MR = nullptr;
3361 state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr,
3362 /*Result=*/nullptr,
3363 /*OutRegionWithAdjustments=*/&MR);
3364 SVal baseExprVal =
3365 MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx);
3366
3367 // FIXME: Copied from RegionStoreManager::bind()
3368 if (const auto *SR =
3369 dyn_cast_or_null<SymbolicRegion>(baseExprVal.getAsRegion())) {
3370 QualType T = SR->getPointeeStaticType();
3371 baseExprVal =
3372 loc::MemRegionVal(getStoreManager().GetElementZeroRegion(SR, T));
3373 }
3374
3375 const auto *field = cast<FieldDecl>(Member);
3376 SVal L = state->getLValue(field, baseExprVal);
3377
3378 if (M->isGLValue() || M->getType()->isArrayType()) {
3379 // We special-case rvalues of array type because the analyzer cannot
3380 // reason about them, since we expect all regions to be wrapped in Locs.
3381 // We instead treat these as lvalues and assume that they will decay to
3382 // pointers as soon as they are used.
3383 if (!M->isGLValue()) {
3384 assert(M->getType()->isArrayType());
3385 const auto *PE =
3386 dyn_cast<ImplicitCastExpr>(I->getParentMap().getParentIgnoreParens(M));
3387 if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
3388 llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
3389 }
3390 }
3391
3392 if (field->getType()->isReferenceType()) {
3393 if (const MemRegion *R = L.getAsRegion())
3394 L = state->getSVal(R);
3395 else
3396 L = UnknownVal();
3397 }
3398
3399 Bldr.generateNode(M, I, state->BindExpr(M, LCtx, L), nullptr,
3400 ProgramPoint::PostLValueKind);
3401 } else {
3402 Bldr.takeNodes(I);
3403 evalLoad(Tmp, M, M, I, state, L);
3404 Bldr.addNodes(Tmp);
3405 }
3406 }
3407 }
3408
3409 getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this);
3410 }
3411
VisitAtomicExpr(const AtomicExpr * AE,ExplodedNode * Pred,ExplodedNodeSet & Dst)3412 void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
3413 ExplodedNodeSet &Dst) {
3414 ExplodedNodeSet AfterPreSet;
3415 getCheckerManager().runCheckersForPreStmt(AfterPreSet, Pred, AE, *this);
3416
3417 // For now, treat all the arguments to C11 atomics as escaping.
3418 // FIXME: Ideally we should model the behavior of the atomics precisely here.
3419
3420 ExplodedNodeSet AfterInvalidateSet;
3421 StmtNodeBuilder Bldr(AfterPreSet, AfterInvalidateSet, *currBldrCtx);
3422
3423 for (const auto I : AfterPreSet) {
3424 ProgramStateRef State = I->getState();
3425 const LocationContext *LCtx = I->getLocationContext();
3426
3427 SmallVector<SVal, 8> ValuesToInvalidate;
3428 for (unsigned SI = 0, Count = AE->getNumSubExprs(); SI != Count; SI++) {
3429 const Expr *SubExpr = AE->getSubExprs()[SI];
3430 SVal SubExprVal = State->getSVal(SubExpr, LCtx);
3431 ValuesToInvalidate.push_back(SubExprVal);
3432 }
3433
3434 State = State->invalidateRegions(ValuesToInvalidate, AE,
3435 currBldrCtx->blockCount(),
3436 LCtx,
3437 /*CausedByPointerEscape*/true,
3438 /*Symbols=*/nullptr);
3439
3440 SVal ResultVal = UnknownVal();
3441 State = State->BindExpr(AE, LCtx, ResultVal);
3442 Bldr.generateNode(AE, I, State, nullptr,
3443 ProgramPoint::PostStmtKind);
3444 }
3445
3446 getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this);
3447 }
3448
3449 // A value escapes in four possible cases:
3450 // (1) We are binding to something that is not a memory region.
3451 // (2) We are binding to a MemRegion that does not have stack storage.
3452 // (3) We are binding to a top-level parameter region with a non-trivial
3453 // destructor. We won't see the destructor during analysis, but it's there.
3454 // (4) We are binding to a MemRegion with stack storage that the store
3455 // does not understand.
processPointerEscapedOnBind(ProgramStateRef State,ArrayRef<std::pair<SVal,SVal>> LocAndVals,const LocationContext * LCtx,PointerEscapeKind Kind,const CallEvent * Call)3456 ProgramStateRef ExprEngine::processPointerEscapedOnBind(
3457 ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
3458 const LocationContext *LCtx, PointerEscapeKind Kind,
3459 const CallEvent *Call) {
3460 SmallVector<SVal, 8> Escaped;
3461 for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
3462 // Cases (1) and (2).
3463 const MemRegion *MR = LocAndVal.first.getAsRegion();
3464 if (!MR ||
3465 !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MR->getMemorySpace())) {
3466 Escaped.push_back(LocAndVal.second);
3467 continue;
3468 }
3469
3470 // Case (3).
3471 if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
3472 if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
3473 if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
3474 if (!RD->hasTrivialDestructor()) {
3475 Escaped.push_back(LocAndVal.second);
3476 continue;
3477 }
3478
3479 // Case (4): in order to test that, generate a new state with the binding
3480 // added. If it is the same state, then it escapes (since the store cannot
3481 // represent the binding).
3482 // Do this only if we know that the store is not supposed to generate the
3483 // same state.
3484 SVal StoredVal = State->getSVal(MR);
3485 if (StoredVal != LocAndVal.second)
3486 if (State ==
3487 (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx)))
3488 Escaped.push_back(LocAndVal.second);
3489 }
3490
3491 if (Escaped.empty())
3492 return State;
3493
3494 return escapeValues(State, Escaped, Kind, Call);
3495 }
3496
3497 ProgramStateRef
processPointerEscapedOnBind(ProgramStateRef State,SVal Loc,SVal Val,const LocationContext * LCtx)3498 ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
3499 SVal Val, const LocationContext *LCtx) {
3500 std::pair<SVal, SVal> LocAndVal(Loc, Val);
3501 return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind,
3502 nullptr);
3503 }
3504
3505 ProgramStateRef
notifyCheckersOfPointerEscape(ProgramStateRef State,const InvalidatedSymbols * Invalidated,ArrayRef<const MemRegion * > ExplicitRegions,const CallEvent * Call,RegionAndSymbolInvalidationTraits & ITraits)3506 ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
3507 const InvalidatedSymbols *Invalidated,
3508 ArrayRef<const MemRegion *> ExplicitRegions,
3509 const CallEvent *Call,
3510 RegionAndSymbolInvalidationTraits &ITraits) {
3511 if (!Invalidated || Invalidated->empty())
3512 return State;
3513
3514 if (!Call)
3515 return getCheckerManager().runCheckersForPointerEscape(State,
3516 *Invalidated,
3517 nullptr,
3518 PSK_EscapeOther,
3519 &ITraits);
3520
3521 // If the symbols were invalidated by a call, we want to find out which ones
3522 // were invalidated directly due to being arguments to the call.
3523 InvalidatedSymbols SymbolsDirectlyInvalidated;
3524 for (const auto I : ExplicitRegions) {
3525 if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>())
3526 SymbolsDirectlyInvalidated.insert(R->getSymbol());
3527 }
3528
3529 InvalidatedSymbols SymbolsIndirectlyInvalidated;
3530 for (const auto &sym : *Invalidated) {
3531 if (SymbolsDirectlyInvalidated.count(sym))
3532 continue;
3533 SymbolsIndirectlyInvalidated.insert(sym);
3534 }
3535
3536 if (!SymbolsDirectlyInvalidated.empty())
3537 State = getCheckerManager().runCheckersForPointerEscape(State,
3538 SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall, &ITraits);
3539
3540 // Notify about the symbols that get indirectly invalidated by the call.
3541 if (!SymbolsIndirectlyInvalidated.empty())
3542 State = getCheckerManager().runCheckersForPointerEscape(State,
3543 SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall, &ITraits);
3544
3545 return State;
3546 }
3547
3548 /// evalBind - Handle the semantics of binding a value to a specific location.
3549 /// This method is used by evalStore and (soon) VisitDeclStmt, and others.
evalBind(ExplodedNodeSet & Dst,const Stmt * StoreE,ExplodedNode * Pred,SVal location,SVal Val,bool atDeclInit,const ProgramPoint * PP)3550 void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
3551 ExplodedNode *Pred,
3552 SVal location, SVal Val,
3553 bool atDeclInit, const ProgramPoint *PP) {
3554 const LocationContext *LC = Pred->getLocationContext();
3555 PostStmt PS(StoreE, LC);
3556 if (!PP)
3557 PP = &PS;
3558
3559 // Do a previsit of the bind.
3560 ExplodedNodeSet CheckedSet;
3561 getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
3562 StoreE, *this, *PP);
3563
3564 StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx);
3565
3566 // If the location is not a 'Loc', it will already be handled by
3567 // the checkers. There is nothing left to do.
3568 if (!isa<Loc>(location)) {
3569 const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr,
3570 /*tag*/nullptr);
3571 ProgramStateRef state = Pred->getState();
3572 state = processPointerEscapedOnBind(state, location, Val, LC);
3573 Bldr.generateNode(L, state, Pred);
3574 return;
3575 }
3576
3577 for (const auto PredI : CheckedSet) {
3578 ProgramStateRef state = PredI->getState();
3579
3580 state = processPointerEscapedOnBind(state, location, Val, LC);
3581
3582 // When binding the value, pass on the hint that this is a initialization.
3583 // For initializations, we do not need to inform clients of region
3584 // changes.
3585 state = state->bindLoc(location.castAs<Loc>(),
3586 Val, LC, /* notifyChanges = */ !atDeclInit);
3587
3588 const MemRegion *LocReg = nullptr;
3589 if (std::optional<loc::MemRegionVal> LocRegVal =
3590 location.getAs<loc::MemRegionVal>()) {
3591 LocReg = LocRegVal->getRegion();
3592 }
3593
3594 const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr);
3595 Bldr.generateNode(L, state, PredI);
3596 }
3597 }
3598
3599 /// evalStore - Handle the semantics of a store via an assignment.
3600 /// @param Dst The node set to store generated state nodes
3601 /// @param AssignE The assignment expression if the store happens in an
3602 /// assignment.
3603 /// @param LocationE The location expression that is stored to.
3604 /// @param state The current simulation state
3605 /// @param location The location to store the value
3606 /// @param Val The value to be stored
evalStore(ExplodedNodeSet & Dst,const Expr * AssignE,const Expr * LocationE,ExplodedNode * Pred,ProgramStateRef state,SVal location,SVal Val,const ProgramPointTag * tag)3607 void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
3608 const Expr *LocationE,
3609 ExplodedNode *Pred,
3610 ProgramStateRef state, SVal location, SVal Val,
3611 const ProgramPointTag *tag) {
3612 // Proceed with the store. We use AssignE as the anchor for the PostStore
3613 // ProgramPoint if it is non-NULL, and LocationE otherwise.
3614 const Expr *StoreE = AssignE ? AssignE : LocationE;
3615
3616 // Evaluate the location (checks for bad dereferences).
3617 ExplodedNodeSet Tmp;
3618 evalLocation(Tmp, AssignE, LocationE, Pred, state, location, false);
3619
3620 if (Tmp.empty())
3621 return;
3622
3623 if (location.isUndef())
3624 return;
3625
3626 for (const auto I : Tmp)
3627 evalBind(Dst, StoreE, I, location, Val, false);
3628 }
3629
evalLoad(ExplodedNodeSet & Dst,const Expr * NodeEx,const Expr * BoundEx,ExplodedNode * Pred,ProgramStateRef state,SVal location,const ProgramPointTag * tag,QualType LoadTy)3630 void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
3631 const Expr *NodeEx,
3632 const Expr *BoundEx,
3633 ExplodedNode *Pred,
3634 ProgramStateRef state,
3635 SVal location,
3636 const ProgramPointTag *tag,
3637 QualType LoadTy) {
3638 assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
3639 assert(NodeEx);
3640 assert(BoundEx);
3641 // Evaluate the location (checks for bad dereferences).
3642 ExplodedNodeSet Tmp;
3643 evalLocation(Tmp, NodeEx, BoundEx, Pred, state, location, true);
3644 if (Tmp.empty())
3645 return;
3646
3647 StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
3648 if (location.isUndef())
3649 return;
3650
3651 // Proceed with the load.
3652 for (const auto I : Tmp) {
3653 state = I->getState();
3654 const LocationContext *LCtx = I->getLocationContext();
3655
3656 SVal V = UnknownVal();
3657 if (location.isValid()) {
3658 if (LoadTy.isNull())
3659 LoadTy = BoundEx->getType();
3660 V = state->getSVal(location.castAs<Loc>(), LoadTy);
3661 }
3662
3663 Bldr.generateNode(NodeEx, I, state->BindExpr(BoundEx, LCtx, V), tag,
3664 ProgramPoint::PostLoadKind);
3665 }
3666 }
3667
evalLocation(ExplodedNodeSet & Dst,const Stmt * NodeEx,const Stmt * BoundEx,ExplodedNode * Pred,ProgramStateRef state,SVal location,bool isLoad)3668 void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
3669 const Stmt *NodeEx,
3670 const Stmt *BoundEx,
3671 ExplodedNode *Pred,
3672 ProgramStateRef state,
3673 SVal location,
3674 bool isLoad) {
3675 StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
3676 // Early checks for performance reason.
3677 if (location.isUnknown()) {
3678 return;
3679 }
3680
3681 ExplodedNodeSet Src;
3682 BldrTop.takeNodes(Pred);
3683 StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx);
3684 if (Pred->getState() != state) {
3685 // Associate this new state with an ExplodedNode.
3686 // FIXME: If I pass null tag, the graph is incorrect, e.g for
3687 // int *p;
3688 // p = 0;
3689 // *p = 0xDEADBEEF;
3690 // "p = 0" is not noted as "Null pointer value stored to 'p'" but
3691 // instead "int *p" is noted as
3692 // "Variable 'p' initialized to a null pointer value"
3693
3694 static SimpleProgramPointTag tag(TagProviderName, "Location");
3695 Bldr.generateNode(NodeEx, Pred, state, &tag);
3696 }
3697 ExplodedNodeSet Tmp;
3698 getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
3699 NodeEx, BoundEx, *this);
3700 BldrTop.addNodes(Tmp);
3701 }
3702
3703 std::pair<const ProgramPointTag *, const ProgramPointTag*>
geteagerlyAssumeBinOpBifurcationTags()3704 ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
3705 static SimpleProgramPointTag
3706 eagerlyAssumeBinOpBifurcationTrue(TagProviderName,
3707 "Eagerly Assume True"),
3708 eagerlyAssumeBinOpBifurcationFalse(TagProviderName,
3709 "Eagerly Assume False");
3710 return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
3711 &eagerlyAssumeBinOpBifurcationFalse);
3712 }
3713
evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet & Dst,ExplodedNodeSet & Src,const Expr * Ex)3714 void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
3715 ExplodedNodeSet &Src,
3716 const Expr *Ex) {
3717 StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
3718
3719 for (const auto Pred : Src) {
3720 // Test if the previous node was as the same expression. This can happen
3721 // when the expression fails to evaluate to anything meaningful and
3722 // (as an optimization) we don't generate a node.
3723 ProgramPoint P = Pred->getLocation();
3724 if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
3725 continue;
3726 }
3727
3728 ProgramStateRef state = Pred->getState();
3729 SVal V = state->getSVal(Ex, Pred->getLocationContext());
3730 std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
3731 if (SEV && SEV->isExpression()) {
3732 const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
3733 geteagerlyAssumeBinOpBifurcationTags();
3734
3735 ProgramStateRef StateTrue, StateFalse;
3736 std::tie(StateTrue, StateFalse) = state->assume(*SEV);
3737
3738 // First assume that the condition is true.
3739 if (StateTrue) {
3740 SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
3741 StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
3742 Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
3743 }
3744
3745 // Next, assume that the condition is false.
3746 if (StateFalse) {
3747 SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
3748 StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
3749 Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
3750 }
3751 }
3752 }
3753 }
3754
VisitGCCAsmStmt(const GCCAsmStmt * A,ExplodedNode * Pred,ExplodedNodeSet & Dst)3755 void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
3756 ExplodedNodeSet &Dst) {
3757 StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
3758 // We have processed both the inputs and the outputs. All of the outputs
3759 // should evaluate to Locs. Nuke all of their values.
3760
3761 // FIXME: Some day in the future it would be nice to allow a "plug-in"
3762 // which interprets the inline asm and stores proper results in the
3763 // outputs.
3764
3765 ProgramStateRef state = Pred->getState();
3766
3767 for (const Expr *O : A->outputs()) {
3768 SVal X = state->getSVal(O, Pred->getLocationContext());
3769 assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
3770
3771 if (std::optional<Loc> LV = X.getAs<Loc>())
3772 state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext());
3773 }
3774
3775 Bldr.generateNode(A, Pred, state);
3776 }
3777
VisitMSAsmStmt(const MSAsmStmt * A,ExplodedNode * Pred,ExplodedNodeSet & Dst)3778 void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
3779 ExplodedNodeSet &Dst) {
3780 StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
3781 Bldr.generateNode(A, Pred, Pred->getState());
3782 }
3783
3784 //===----------------------------------------------------------------------===//
3785 // Visualization.
3786 //===----------------------------------------------------------------------===//
3787
3788 namespace llvm {
3789
3790 template<>
3791 struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits3792 DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
3793
nodeHasBugReportllvm::DOTGraphTraits3794 static bool nodeHasBugReport(const ExplodedNode *N) {
3795 BugReporter &BR = static_cast<ExprEngine &>(
3796 N->getState()->getStateManager().getOwningEngine()).getBugReporter();
3797
3798 const auto EQClasses =
3799 llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end());
3800
3801 for (const auto &EQ : EQClasses) {
3802 for (const auto &I : EQ.getReports()) {
3803 const auto *PR = dyn_cast<PathSensitiveBugReport>(I.get());
3804 if (!PR)
3805 continue;
3806 const ExplodedNode *EN = PR->getErrorNode();
3807 if (EN->getState() == N->getState() &&
3808 EN->getLocation() == N->getLocation())
3809 return true;
3810 }
3811 }
3812 return false;
3813 }
3814
3815 /// \p PreCallback: callback before break.
3816 /// \p PostCallback: callback after break.
3817 /// \p Stop: stop iteration if returns @c true
3818 /// \return Whether @c Stop ever returned @c true.
traverseHiddenNodesllvm::DOTGraphTraits3819 static bool traverseHiddenNodes(
3820 const ExplodedNode *N,
3821 llvm::function_ref<void(const ExplodedNode *)> PreCallback,
3822 llvm::function_ref<void(const ExplodedNode *)> PostCallback,
3823 llvm::function_ref<bool(const ExplodedNode *)> Stop) {
3824 while (true) {
3825 PreCallback(N);
3826 if (Stop(N))
3827 return true;
3828
3829 if (N->succ_size() != 1 || !isNodeHidden(N->getFirstSucc(), nullptr))
3830 break;
3831 PostCallback(N);
3832
3833 N = N->getFirstSucc();
3834 }
3835 return false;
3836 }
3837
isNodeHiddenllvm::DOTGraphTraits3838 static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) {
3839 return N->isTrivial();
3840 }
3841
getNodeLabelllvm::DOTGraphTraits3842 static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){
3843 std::string Buf;
3844 llvm::raw_string_ostream Out(Buf);
3845
3846 const bool IsDot = true;
3847 const unsigned int Space = 1;
3848 ProgramStateRef State = N->getState();
3849
3850 Out << "{ \"state_id\": " << State->getID()
3851 << ",\\l";
3852
3853 Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
3854
3855 // Dump program point for all the previously skipped nodes.
3856 traverseHiddenNodes(
3857 N,
3858 [&](const ExplodedNode *OtherNode) {
3859 Indent(Out, Space + 1, IsDot) << "{ ";
3860 OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
3861 Out << ", \"tag\": ";
3862 if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
3863 Out << '\"' << Tag->getTagDescription() << '\"';
3864 else
3865 Out << "null";
3866 Out << ", \"node_id\": " << OtherNode->getID() <<
3867 ", \"is_sink\": " << OtherNode->isSink() <<
3868 ", \"has_report\": " << nodeHasBugReport(OtherNode) << " }";
3869 },
3870 // Adds a comma and a new-line between each program point.
3871 [&](const ExplodedNode *) { Out << ",\\l"; },
3872 [&](const ExplodedNode *) { return false; });
3873
3874 Out << "\\l"; // Adds a new-line to the last program point.
3875 Indent(Out, Space, IsDot) << "],\\l";
3876
3877 State->printDOT(Out, N->getLocationContext(), Space);
3878
3879 Out << "\\l}\\l";
3880 return Out.str();
3881 }
3882 };
3883
3884 } // namespace llvm
3885
ViewGraph(bool trim)3886 void ExprEngine::ViewGraph(bool trim) {
3887 std::string Filename = DumpGraph(trim);
3888 llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT);
3889 }
3890
ViewGraph(ArrayRef<const ExplodedNode * > Nodes)3891 void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode *> Nodes) {
3892 std::string Filename = DumpGraph(Nodes);
3893 llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT);
3894 }
3895
DumpGraph(bool trim,StringRef Filename)3896 std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
3897 if (trim) {
3898 std::vector<const ExplodedNode *> Src;
3899
3900 // Iterate through the reports and get their nodes.
3901 for (BugReporter::EQClasses_iterator
3902 EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
3903 const auto *R =
3904 dyn_cast<PathSensitiveBugReport>(EI->getReports()[0].get());
3905 if (!R)
3906 continue;
3907 const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
3908 Src.push_back(N);
3909 }
3910 return DumpGraph(Src, Filename);
3911 }
3912
3913 return llvm::WriteGraph(&G, "ExprEngine", /*ShortNames=*/false,
3914 /*Title=*/"Exploded Graph",
3915 /*Filename=*/std::string(Filename));
3916 }
3917
DumpGraph(ArrayRef<const ExplodedNode * > Nodes,StringRef Filename)3918 std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes,
3919 StringRef Filename) {
3920 std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
3921
3922 if (!TrimmedG.get()) {
3923 llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
3924 return "";
3925 }
3926
3927 return llvm::WriteGraph(TrimmedG.get(), "TrimmedExprEngine",
3928 /*ShortNames=*/false,
3929 /*Title=*/"Trimmed Exploded Graph",
3930 /*Filename=*/std::string(Filename));
3931 }
3932
GDMIndex()3933 void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() {
3934 static int index = 0;
3935 return &index;
3936 }
3937
anchor()3938 void ExprEngine::anchor() { }
3939