1 //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
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 an Environment class that is used by dataflow analyses
10 // that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11 // program at given program points.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/Stmt.h"
20 #include "clang/AST/Type.h"
21 #include "clang/Analysis/FlowSensitive/ASTOps.h"
22 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
23 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
24 #include "clang/Analysis/FlowSensitive/Value.h"
25 #include "llvm/ADT/DenseMap.h"
26 #include "llvm/ADT/DenseSet.h"
27 #include "llvm/ADT/MapVector.h"
28 #include "llvm/ADT/STLExtras.h"
29 #include "llvm/ADT/ScopeExit.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include <cassert>
32 #include <memory>
33 #include <utility>
34
35 #define DEBUG_TYPE "dataflow"
36
37 namespace clang {
38 namespace dataflow {
39
40 // FIXME: convert these to parameters of the analysis or environment. Current
41 // settings have been experimentaly validated, but only for a particular
42 // analysis.
43 static constexpr int MaxCompositeValueDepth = 3;
44 static constexpr int MaxCompositeValueSize = 1000;
45
46 /// Returns a map consisting of key-value entries that are present in both maps.
intersectDeclToLoc(const llvm::DenseMap<const ValueDecl *,StorageLocation * > & DeclToLoc1,const llvm::DenseMap<const ValueDecl *,StorageLocation * > & DeclToLoc2)47 static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
48 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
49 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
50 llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;
51 for (auto &Entry : DeclToLoc1) {
52 auto It = DeclToLoc2.find(Entry.first);
53 if (It != DeclToLoc2.end() && Entry.second == It->second)
54 Result.insert({Entry.first, Entry.second});
55 }
56 return Result;
57 }
58
59 // Performs a join on either `ExprToLoc` or `ExprToVal`.
60 // The maps must be consistent in the sense that any entries for the same
61 // expression must map to the same location / value. This is the case if we are
62 // performing a join for control flow within a full-expression (which is the
63 // only case when this function should be used).
64 template <typename MapT>
joinExprMaps(const MapT & Map1,const MapT & Map2)65 static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
66 MapT Result = Map1;
67
68 for (const auto &Entry : Map2) {
69 [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
70 // If there was an existing entry, its value should be the same as for the
71 // entry we were trying to insert.
72 assert(It->second == Entry.second);
73 }
74
75 return Result;
76 }
77
78 // Whether to consider equivalent two values with an unknown relation.
79 //
80 // FIXME: this function is a hack enabling unsoundness to support
81 // convergence. Once we have widening support for the reference/pointer and
82 // struct built-in models, this should be unconditionally `false` (and inlined
83 // as such at its call sites).
equateUnknownValues(Value::Kind K)84 static bool equateUnknownValues(Value::Kind K) {
85 switch (K) {
86 case Value::Kind::Integer:
87 case Value::Kind::Pointer:
88 return true;
89 default:
90 return false;
91 }
92 }
93
compareDistinctValues(QualType Type,Value & Val1,const Environment & Env1,Value & Val2,const Environment & Env2,Environment::ValueModel & Model)94 static bool compareDistinctValues(QualType Type, Value &Val1,
95 const Environment &Env1, Value &Val2,
96 const Environment &Env2,
97 Environment::ValueModel &Model) {
98 // Note: Potentially costly, but, for booleans, we could check whether both
99 // can be proven equivalent in their respective environments.
100
101 // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
102 // and implement separate, join/widen specific handling for
103 // reference/pointers.
104 switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
105 case ComparisonResult::Same:
106 return true;
107 case ComparisonResult::Different:
108 return false;
109 case ComparisonResult::Unknown:
110 return equateUnknownValues(Val1.getKind());
111 }
112 llvm_unreachable("All cases covered in switch");
113 }
114
115 /// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,
116 /// respectively, of the same type `Type`. Joining generally produces a single
117 /// value that (soundly) approximates the two inputs, although the actual
118 /// meaning depends on `Model`.
joinDistinctValues(QualType Type,Value & Val1,const Environment & Env1,Value & Val2,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)119 static Value *joinDistinctValues(QualType Type, Value &Val1,
120 const Environment &Env1, Value &Val2,
121 const Environment &Env2,
122 Environment &JoinedEnv,
123 Environment::ValueModel &Model) {
124 // Join distinct boolean values preserving information about the constraints
125 // in the respective path conditions.
126 if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
127 // FIXME: Checking both values should be unnecessary, since they should have
128 // a consistent shape. However, right now we can end up with BoolValue's in
129 // integer-typed variables due to our incorrect handling of
130 // boolean-to-integer casts (we just propagate the BoolValue to the result
131 // of the cast). So, a join can encounter an integer in one branch but a
132 // bool in the other.
133 // For example:
134 // ```
135 // std::optional<bool> o;
136 // int x;
137 // if (o.has_value())
138 // x = o.value();
139 // ```
140 auto &Expr1 = cast<BoolValue>(Val1).formula();
141 auto &Expr2 = cast<BoolValue>(Val2).formula();
142 auto &A = JoinedEnv.arena();
143 auto &JoinedVal = A.makeAtomRef(A.makeAtom());
144 JoinedEnv.assume(
145 A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
146 A.makeEquals(JoinedVal, Expr1)),
147 A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
148 A.makeEquals(JoinedVal, Expr2))));
149 return &A.makeBoolValue(JoinedVal);
150 }
151
152 Value *JoinedVal = JoinedEnv.createValue(Type);
153 if (JoinedVal)
154 Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
155
156 return JoinedVal;
157 }
158
widenDistinctValues(QualType Type,Value & Prev,const Environment & PrevEnv,Value & Current,Environment & CurrentEnv,Environment::ValueModel & Model)159 static WidenResult widenDistinctValues(QualType Type, Value &Prev,
160 const Environment &PrevEnv,
161 Value &Current, Environment &CurrentEnv,
162 Environment::ValueModel &Model) {
163 // Boolean-model widening.
164 if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
165 // FIXME: Checking both values should be unnecessary, but we can currently
166 // end up with `BoolValue`s in integer-typed variables. See comment in
167 // `joinDistinctValues()` for details.
168 auto &PrevBool = cast<BoolValue>(Prev);
169 auto &CurBool = cast<BoolValue>(Current);
170
171 if (isa<TopBoolValue>(Prev))
172 // Safe to return `Prev` here, because Top is never dependent on the
173 // environment.
174 return {&Prev, LatticeEffect::Unchanged};
175
176 // We may need to widen to Top, but before we do so, check whether both
177 // values are implied to be either true or false in the current environment.
178 // In that case, we can simply return a literal instead.
179 bool TruePrev = PrevEnv.proves(PrevBool.formula());
180 bool TrueCur = CurrentEnv.proves(CurBool.formula());
181 if (TruePrev && TrueCur)
182 return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged};
183 if (!TruePrev && !TrueCur &&
184 PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) &&
185 CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula())))
186 return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged};
187
188 return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed};
189 }
190
191 // FIXME: Add other built-in model widening.
192
193 // Custom-model widening.
194 if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
195 return *Result;
196
197 return {&Current, equateUnknownValues(Prev.getKind())
198 ? LatticeEffect::Unchanged
199 : LatticeEffect::Changed};
200 }
201
202 // Returns whether the values in `Map1` and `Map2` compare equal for those
203 // keys that `Map1` and `Map2` have in common.
204 template <typename Key>
compareKeyToValueMaps(const llvm::MapVector<Key,Value * > & Map1,const llvm::MapVector<Key,Value * > & Map2,const Environment & Env1,const Environment & Env2,Environment::ValueModel & Model)205 static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
206 const llvm::MapVector<Key, Value *> &Map2,
207 const Environment &Env1,
208 const Environment &Env2,
209 Environment::ValueModel &Model) {
210 for (auto &Entry : Map1) {
211 Key K = Entry.first;
212 assert(K != nullptr);
213
214 Value *Val = Entry.second;
215 assert(Val != nullptr);
216
217 auto It = Map2.find(K);
218 if (It == Map2.end())
219 continue;
220 assert(It->second != nullptr);
221
222 if (!areEquivalentValues(*Val, *It->second) &&
223 !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,
224 Model))
225 return false;
226 }
227
228 return true;
229 }
230
231 // Perform a join on two `LocToVal` maps.
232 static llvm::MapVector<const StorageLocation *, Value *>
joinLocToVal(const llvm::MapVector<const StorageLocation *,Value * > & LocToVal,const llvm::MapVector<const StorageLocation *,Value * > & LocToVal2,const Environment & Env1,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)233 joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
234 const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
235 const Environment &Env1, const Environment &Env2,
236 Environment &JoinedEnv, Environment::ValueModel &Model) {
237 llvm::MapVector<const StorageLocation *, Value *> Result;
238 for (auto &Entry : LocToVal) {
239 const StorageLocation *Loc = Entry.first;
240 assert(Loc != nullptr);
241
242 Value *Val = Entry.second;
243 assert(Val != nullptr);
244
245 auto It = LocToVal2.find(Loc);
246 if (It == LocToVal2.end())
247 continue;
248 assert(It->second != nullptr);
249
250 if (Value *JoinedVal = Environment::joinValues(
251 Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
252 Result.insert({Loc, JoinedVal});
253 }
254 }
255
256 return Result;
257 }
258
259 // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
260 // `const StorageLocation *` or `const Expr *`.
261 template <typename Key>
262 static llvm::MapVector<Key, Value *>
widenKeyToValueMap(const llvm::MapVector<Key,Value * > & CurMap,const llvm::MapVector<Key,Value * > & PrevMap,Environment & CurEnv,const Environment & PrevEnv,Environment::ValueModel & Model,LatticeEffect & Effect)263 widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
264 const llvm::MapVector<Key, Value *> &PrevMap,
265 Environment &CurEnv, const Environment &PrevEnv,
266 Environment::ValueModel &Model, LatticeEffect &Effect) {
267 llvm::MapVector<Key, Value *> WidenedMap;
268 for (auto &Entry : CurMap) {
269 Key K = Entry.first;
270 assert(K != nullptr);
271
272 Value *Val = Entry.second;
273 assert(Val != nullptr);
274
275 auto PrevIt = PrevMap.find(K);
276 if (PrevIt == PrevMap.end())
277 continue;
278 assert(PrevIt->second != nullptr);
279
280 if (areEquivalentValues(*Val, *PrevIt->second)) {
281 WidenedMap.insert({K, Val});
282 continue;
283 }
284
285 auto [WidenedVal, ValEffect] = widenDistinctValues(
286 K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
287 WidenedMap.insert({K, WidenedVal});
288 if (ValEffect == LatticeEffect::Changed)
289 Effect = LatticeEffect::Changed;
290 }
291
292 return WidenedMap;
293 }
294
295 namespace {
296
297 // Visitor that builds a map from record prvalues to result objects.
298 // For each result object that it encounters, it propagates the storage location
299 // of the result object to all record prvalues that can initialize it.
300 class ResultObjectVisitor : public AnalysisASTVisitor {
301 public:
302 // `ResultObjectMap` will be filled with a map from record prvalues to result
303 // object. If this visitor will traverse a function that returns a record by
304 // value, `LocForRecordReturnVal` is the location to which this record should
305 // be written; otherwise, it is null.
ResultObjectVisitor(llvm::DenseMap<const Expr *,RecordStorageLocation * > & ResultObjectMap,RecordStorageLocation * LocForRecordReturnVal,DataflowAnalysisContext & DACtx)306 explicit ResultObjectVisitor(
307 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
308 RecordStorageLocation *LocForRecordReturnVal,
309 DataflowAnalysisContext &DACtx)
310 : ResultObjectMap(ResultObjectMap),
311 LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
312
313 // Traverse all member and base initializers of `Ctor`. This function is not
314 // called by `RecursiveASTVisitor`; it should be called manually if we are
315 // analyzing a constructor. `ThisPointeeLoc` is the storage location that
316 // `this` points to.
traverseConstructorInits(const CXXConstructorDecl * Ctor,RecordStorageLocation * ThisPointeeLoc)317 void traverseConstructorInits(const CXXConstructorDecl *Ctor,
318 RecordStorageLocation *ThisPointeeLoc) {
319 assert(ThisPointeeLoc != nullptr);
320 for (const CXXCtorInitializer *Init : Ctor->inits()) {
321 Expr *InitExpr = Init->getInit();
322 if (FieldDecl *Field = Init->getMember();
323 Field != nullptr && Field->getType()->isRecordType()) {
324 PropagateResultObject(InitExpr, cast<RecordStorageLocation>(
325 ThisPointeeLoc->getChild(*Field)));
326 } else if (Init->getBaseClass()) {
327 PropagateResultObject(InitExpr, ThisPointeeLoc);
328 }
329
330 // Ensure that any result objects within `InitExpr` (e.g. temporaries)
331 // are also propagated to the prvalues that initialize them.
332 TraverseStmt(InitExpr);
333
334 // If this is a `CXXDefaultInitExpr`, also propagate any result objects
335 // within the default expression.
336 if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
337 TraverseStmt(DefaultInit->getExpr());
338 }
339 }
340
VisitVarDecl(VarDecl * VD)341 bool VisitVarDecl(VarDecl *VD) override {
342 if (VD->getType()->isRecordType() && VD->hasInit())
343 PropagateResultObject(
344 VD->getInit(),
345 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));
346 return true;
347 }
348
VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr * MTE)349 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override {
350 if (MTE->getType()->isRecordType())
351 PropagateResultObject(
352 MTE->getSubExpr(),
353 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));
354 return true;
355 }
356
VisitReturnStmt(ReturnStmt * Return)357 bool VisitReturnStmt(ReturnStmt *Return) override {
358 Expr *RetValue = Return->getRetValue();
359 if (RetValue != nullptr && RetValue->getType()->isRecordType() &&
360 RetValue->isPRValue())
361 PropagateResultObject(RetValue, LocForRecordReturnVal);
362 return true;
363 }
364
VisitExpr(Expr * E)365 bool VisitExpr(Expr *E) override {
366 // Clang's AST can have record-type prvalues without a result object -- for
367 // example as full-expressions contained in a compound statement or as
368 // arguments of call expressions. We notice this if we get here and a
369 // storage location has not yet been associated with `E`. In this case,
370 // treat this as if it was a `MaterializeTemporaryExpr`.
371 if (E->isPRValue() && E->getType()->isRecordType() &&
372 !ResultObjectMap.contains(E))
373 PropagateResultObject(
374 E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E)));
375 return true;
376 }
377
378 void
PropagateResultObjectToRecordInitList(const RecordInitListHelper & InitList,RecordStorageLocation * Loc)379 PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,
380 RecordStorageLocation *Loc) {
381 for (auto [Base, Init] : InitList.base_inits()) {
382 assert(Base->getType().getCanonicalType() ==
383 Init->getType().getCanonicalType());
384
385 // Storage location for the base class is the same as that of the
386 // derived class because we "flatten" the object hierarchy and put all
387 // fields in `RecordStorageLocation` of the derived class.
388 PropagateResultObject(Init, Loc);
389 }
390
391 for (auto [Field, Init] : InitList.field_inits()) {
392 // Fields of non-record type are handled in
393 // `TransferVisitor::VisitInitListExpr()`.
394 if (Field->getType()->isRecordType())
395 PropagateResultObject(
396 Init, cast<RecordStorageLocation>(Loc->getChild(*Field)));
397 }
398 }
399
400 // Assigns `Loc` as the result object location of `E`, then propagates the
401 // location to all lower-level prvalues that initialize the same object as
402 // `E` (or one of its base classes or member variables).
PropagateResultObject(Expr * E,RecordStorageLocation * Loc)403 void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
404 if (!E->isPRValue() || !E->getType()->isRecordType()) {
405 assert(false);
406 // Ensure we don't propagate the result object if we hit this in a
407 // release build.
408 return;
409 }
410
411 ResultObjectMap[E] = Loc;
412
413 // The following AST node kinds are "original initializers": They are the
414 // lowest-level AST node that initializes a given object, and nothing
415 // below them can initialize the same object (or part of it).
416 if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
417 isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||
418 isa<AtomicExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) ||
419 // We treat `BuiltinBitCastExpr` as an "original initializer" too as
420 // it may not even be casting from a record type -- and even if it is,
421 // the two objects are in general of unrelated type.
422 isa<BuiltinBitCastExpr>(E)) {
423 return;
424 }
425 if (auto *Op = dyn_cast<BinaryOperator>(E);
426 Op && Op->getOpcode() == BO_Cmp) {
427 // Builtin `<=>` returns a `std::strong_ordering` object.
428 return;
429 }
430
431 if (auto *InitList = dyn_cast<InitListExpr>(E)) {
432 if (!InitList->isSemanticForm())
433 return;
434 if (InitList->isTransparent()) {
435 PropagateResultObject(InitList->getInit(0), Loc);
436 return;
437 }
438
439 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
440 Loc);
441 return;
442 }
443
444 if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {
445 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
446 Loc);
447 return;
448 }
449
450 if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {
451 PropagateResultObject(Op->getRHS(), Loc);
452 return;
453 }
454
455 if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) {
456 PropagateResultObject(Cond->getTrueExpr(), Loc);
457 PropagateResultObject(Cond->getFalseExpr(), Loc);
458 return;
459 }
460
461 if (auto *SE = dyn_cast<StmtExpr>(E)) {
462 PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc);
463 return;
464 }
465
466 if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
467 PropagateResultObject(DIE->getExpr(), Loc);
468 return;
469 }
470
471 // All other expression nodes that propagate a record prvalue should have
472 // exactly one child.
473 SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
474 LLVM_DEBUG({
475 if (Children.size() != 1)
476 E->dump();
477 });
478 assert(Children.size() == 1);
479 for (Stmt *S : Children)
480 PropagateResultObject(cast<Expr>(S), Loc);
481 }
482
483 private:
484 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
485 RecordStorageLocation *LocForRecordReturnVal;
486 DataflowAnalysisContext &DACtx;
487 };
488
489 } // namespace
490
initialize()491 void Environment::initialize() {
492 if (InitialTargetStmt == nullptr)
493 return;
494
495 if (InitialTargetFunc == nullptr) {
496 initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));
497 ResultObjectMap =
498 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
499 DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),
500 /*LocForRecordReturnValue=*/nullptr));
501 return;
502 }
503
504 initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));
505
506 for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
507 assert(ParamDecl != nullptr);
508 setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
509 }
510
511 if (InitialTargetFunc->getReturnType()->isRecordType())
512 LocForRecordReturnVal = &cast<RecordStorageLocation>(
513 createStorageLocation(InitialTargetFunc->getReturnType()));
514
515 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
516 auto *Parent = MethodDecl->getParent();
517 assert(Parent != nullptr);
518
519 if (Parent->isLambda()) {
520 for (const auto &Capture : Parent->captures()) {
521 if (Capture.capturesVariable()) {
522 const auto *VarDecl = Capture.getCapturedVar();
523 assert(VarDecl != nullptr);
524 setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
525 } else if (Capture.capturesThis()) {
526 if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
527 const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
528 QualType ThisPointeeType =
529 SurroundingMethodDecl->getFunctionObjectParameterType();
530 setThisPointeeStorageLocation(
531 cast<RecordStorageLocation>(createObject(ThisPointeeType)));
532 } else if (auto *FieldBeingInitialized =
533 dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
534 // This is in a field initializer, rather than a method.
535 setThisPointeeStorageLocation(
536 cast<RecordStorageLocation>(createObject(QualType(
537 FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
538 } else {
539 assert(false && "Unexpected this-capturing lambda context.");
540 }
541 }
542 }
543 } else if (MethodDecl->isImplicitObjectMemberFunction()) {
544 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
545 auto &ThisLoc =
546 cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
547 setThisPointeeStorageLocation(ThisLoc);
548 // Initialize fields of `*this` with values, but only if we're not
549 // analyzing a constructor; after all, it's the constructor's job to do
550 // this (and we want to be able to test that).
551 if (!isa<CXXConstructorDecl>(MethodDecl))
552 initializeFieldsWithValues(ThisLoc);
553 }
554 }
555
556 // We do this below the handling of `CXXMethodDecl` above so that we can
557 // be sure that the storage location for `this` has been set.
558 ResultObjectMap =
559 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
560 DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),
561 LocForRecordReturnVal));
562 }
563
564 // FIXME: Add support for resetting globals after function calls to enable the
565 // implementation of sound analyses.
566
initFieldsGlobalsAndFuncs(const ReferencedDecls & Referenced)567 void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
568 // These have to be added before the lines that follow to ensure that
569 // `create*` work correctly for structs.
570 DACtx->addModeledFields(Referenced.Fields);
571
572 for (const VarDecl *D : Referenced.Globals) {
573 if (getStorageLocation(*D) != nullptr)
574 continue;
575
576 // We don't run transfer functions on the initializers of global variables,
577 // so they won't be associated with a value or storage location. We
578 // therefore intentionally don't pass an initializer to `createObject()`; in
579 // particular, this ensures that `createObject()` will initialize the fields
580 // of record-type variables with values.
581 setStorageLocation(*D, createObject(*D, nullptr));
582 }
583
584 for (const FunctionDecl *FD : Referenced.Functions) {
585 if (getStorageLocation(*FD) != nullptr)
586 continue;
587 auto &Loc = createStorageLocation(*FD);
588 setStorageLocation(*FD, Loc);
589 }
590 }
591
fork() const592 Environment Environment::fork() const {
593 Environment Copy(*this);
594 Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
595 return Copy;
596 }
597
canDescend(unsigned MaxDepth,const FunctionDecl * Callee) const598 bool Environment::canDescend(unsigned MaxDepth,
599 const FunctionDecl *Callee) const {
600 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
601 }
602
pushCall(const CallExpr * Call) const603 Environment Environment::pushCall(const CallExpr *Call) const {
604 Environment Env(*this);
605
606 if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
607 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
608 if (!isa<CXXThisExpr>(Arg))
609 Env.ThisPointeeLoc =
610 cast<RecordStorageLocation>(getStorageLocation(*Arg));
611 // Otherwise (when the argument is `this`), retain the current
612 // environment's `ThisPointeeLoc`.
613 }
614 }
615
616 if (Call->getType()->isRecordType() && Call->isPRValue())
617 Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
618
619 Env.pushCallInternal(Call->getDirectCallee(),
620 llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
621
622 return Env;
623 }
624
pushCall(const CXXConstructExpr * Call) const625 Environment Environment::pushCall(const CXXConstructExpr *Call) const {
626 Environment Env(*this);
627
628 Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
629 Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
630
631 Env.pushCallInternal(Call->getConstructor(),
632 llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
633
634 return Env;
635 }
636
pushCallInternal(const FunctionDecl * FuncDecl,ArrayRef<const Expr * > Args)637 void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
638 ArrayRef<const Expr *> Args) {
639 // Canonicalize to the definition of the function. This ensures that we're
640 // putting arguments into the same `ParamVarDecl`s` that the callee will later
641 // be retrieving them from.
642 assert(FuncDecl->getDefinition() != nullptr);
643 FuncDecl = FuncDecl->getDefinition();
644
645 CallStack.push_back(FuncDecl);
646
647 initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));
648
649 const auto *ParamIt = FuncDecl->param_begin();
650
651 // FIXME: Parameters don't always map to arguments 1:1; examples include
652 // overloaded operators implemented as member functions, and parameter packs.
653 for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
654 assert(ParamIt != FuncDecl->param_end());
655 const VarDecl *Param = *ParamIt;
656 setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));
657 }
658
659 ResultObjectMap = std::make_shared<PrValueToResultObject>(
660 buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),
661 LocForRecordReturnVal));
662 }
663
popCall(const CallExpr * Call,const Environment & CalleeEnv)664 void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
665 // We ignore some entries of `CalleeEnv`:
666 // - `DACtx` because is already the same in both
667 // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or
668 // `ThisPointeeLoc` because they don't apply to us.
669 // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the
670 // callee's local scope, so when popping that scope, we do not propagate
671 // the maps.
672 this->LocToVal = std::move(CalleeEnv.LocToVal);
673 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
674
675 if (Call->isGLValue()) {
676 if (CalleeEnv.ReturnLoc != nullptr)
677 setStorageLocation(*Call, *CalleeEnv.ReturnLoc);
678 } else if (!Call->getType()->isVoidType()) {
679 if (CalleeEnv.ReturnVal != nullptr)
680 setValue(*Call, *CalleeEnv.ReturnVal);
681 }
682 }
683
popCall(const CXXConstructExpr * Call,const Environment & CalleeEnv)684 void Environment::popCall(const CXXConstructExpr *Call,
685 const Environment &CalleeEnv) {
686 // See also comment in `popCall(const CallExpr *, const Environment &)` above.
687 this->LocToVal = std::move(CalleeEnv.LocToVal);
688 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
689 }
690
equivalentTo(const Environment & Other,Environment::ValueModel & Model) const691 bool Environment::equivalentTo(const Environment &Other,
692 Environment::ValueModel &Model) const {
693 assert(DACtx == Other.DACtx);
694
695 if (ReturnVal != Other.ReturnVal)
696 return false;
697
698 if (ReturnLoc != Other.ReturnLoc)
699 return false;
700
701 if (LocForRecordReturnVal != Other.LocForRecordReturnVal)
702 return false;
703
704 if (ThisPointeeLoc != Other.ThisPointeeLoc)
705 return false;
706
707 if (DeclToLoc != Other.DeclToLoc)
708 return false;
709
710 if (ExprToLoc != Other.ExprToLoc)
711 return false;
712
713 if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model))
714 return false;
715
716 if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model))
717 return false;
718
719 return true;
720 }
721
widen(const Environment & PrevEnv,Environment::ValueModel & Model)722 LatticeEffect Environment::widen(const Environment &PrevEnv,
723 Environment::ValueModel &Model) {
724 assert(DACtx == PrevEnv.DACtx);
725 assert(ReturnVal == PrevEnv.ReturnVal);
726 assert(ReturnLoc == PrevEnv.ReturnLoc);
727 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
728 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
729 assert(CallStack == PrevEnv.CallStack);
730 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
731 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
732 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
733
734 auto Effect = LatticeEffect::Unchanged;
735
736 // By the API, `PrevEnv` is a previous version of the environment for the same
737 // block, so we have some guarantees about its shape. In particular, it will
738 // be the result of a join or widen operation on previous values for this
739 // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that
740 // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain
741 // this property here, we don't need change their current values to widen.
742 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
743 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
744 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
745
746 ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
747 Model, Effect);
748
749 LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
750 Model, Effect);
751 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
752 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
753 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
754 LocToVal.size() != PrevEnv.LocToVal.size())
755 Effect = LatticeEffect::Changed;
756
757 return Effect;
758 }
759
join(const Environment & EnvA,const Environment & EnvB,Environment::ValueModel & Model,ExprJoinBehavior ExprBehavior)760 Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
761 Environment::ValueModel &Model,
762 ExprJoinBehavior ExprBehavior) {
763 assert(EnvA.DACtx == EnvB.DACtx);
764 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
765 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
766 assert(EnvA.CallStack == EnvB.CallStack);
767 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
768 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
769 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
770
771 Environment JoinedEnv(*EnvA.DACtx);
772
773 JoinedEnv.CallStack = EnvA.CallStack;
774 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
775 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
776 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
777 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
778 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
779
780 const FunctionDecl *Func = EnvA.getCurrentFunc();
781 if (!Func) {
782 JoinedEnv.ReturnVal = nullptr;
783 } else {
784 JoinedEnv.ReturnVal =
785 joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
786 EnvB, JoinedEnv, Model);
787 }
788
789 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
790 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
791 else
792 JoinedEnv.ReturnLoc = nullptr;
793
794 JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);
795
796 // FIXME: update join to detect backedges and simplify the flow condition
797 // accordingly.
798 JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
799 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
800
801 JoinedEnv.LocToVal =
802 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
803
804 if (ExprBehavior == KeepExprState) {
805 JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
806 JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
807 }
808
809 return JoinedEnv;
810 }
811
joinValues(QualType Ty,Value * Val1,const Environment & Env1,Value * Val2,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)812 Value *Environment::joinValues(QualType Ty, Value *Val1,
813 const Environment &Env1, Value *Val2,
814 const Environment &Env2, Environment &JoinedEnv,
815 Environment::ValueModel &Model) {
816 if (Val1 == nullptr || Val2 == nullptr)
817 // We can't say anything about the joined value -- even if one of the values
818 // is non-null, we don't want to simply propagate it, because it would be
819 // too specific: Because the other value is null, that means we have no
820 // information at all about the value (i.e. the value is unconstrained).
821 return nullptr;
822
823 if (areEquivalentValues(*Val1, *Val2))
824 // Arbitrarily return one of the two values.
825 return Val1;
826
827 return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
828 }
829
createStorageLocation(QualType Type)830 StorageLocation &Environment::createStorageLocation(QualType Type) {
831 return DACtx->createStorageLocation(Type);
832 }
833
createStorageLocation(const ValueDecl & D)834 StorageLocation &Environment::createStorageLocation(const ValueDecl &D) {
835 // Evaluated declarations are always assigned the same storage locations to
836 // ensure that the environment stabilizes across loop iterations. Storage
837 // locations for evaluated declarations are stored in the analysis context.
838 return DACtx->getStableStorageLocation(D);
839 }
840
createStorageLocation(const Expr & E)841 StorageLocation &Environment::createStorageLocation(const Expr &E) {
842 // Evaluated expressions are always assigned the same storage locations to
843 // ensure that the environment stabilizes across loop iterations. Storage
844 // locations for evaluated expressions are stored in the analysis context.
845 return DACtx->getStableStorageLocation(E);
846 }
847
setStorageLocation(const ValueDecl & D,StorageLocation & Loc)848 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
849 assert(!DeclToLoc.contains(&D));
850 // The only kinds of declarations that may have a "variable" storage location
851 // are declarations of reference type and `BindingDecl`. For all other
852 // declaration, the storage location should be the stable storage location
853 // returned by `createStorageLocation()`.
854 assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) ||
855 &Loc == &createStorageLocation(D));
856 DeclToLoc[&D] = &Loc;
857 }
858
getStorageLocation(const ValueDecl & D) const859 StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
860 auto It = DeclToLoc.find(&D);
861 if (It == DeclToLoc.end())
862 return nullptr;
863
864 StorageLocation *Loc = It->second;
865
866 return Loc;
867 }
868
removeDecl(const ValueDecl & D)869 void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); }
870
setStorageLocation(const Expr & E,StorageLocation & Loc)871 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
872 // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
873 // but we still want to be able to associate a `StorageLocation` with them,
874 // so allow these as an exception.
875 assert(E.isGLValue() ||
876 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
877 const Expr &CanonE = ignoreCFGOmittedNodes(E);
878 assert(!ExprToLoc.contains(&CanonE));
879 ExprToLoc[&CanonE] = &Loc;
880 }
881
getStorageLocation(const Expr & E) const882 StorageLocation *Environment::getStorageLocation(const Expr &E) const {
883 // See comment in `setStorageLocation()`.
884 assert(E.isGLValue() ||
885 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
886 auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
887 return It == ExprToLoc.end() ? nullptr : &*It->second;
888 }
889
890 RecordStorageLocation &
getResultObjectLocation(const Expr & RecordPRValue) const891 Environment::getResultObjectLocation(const Expr &RecordPRValue) const {
892 assert(RecordPRValue.getType()->isRecordType());
893 assert(RecordPRValue.isPRValue());
894
895 assert(ResultObjectMap != nullptr);
896 RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue);
897 assert(Loc != nullptr);
898 // In release builds, use the "stable" storage location if the map lookup
899 // failed.
900 if (Loc == nullptr)
901 return cast<RecordStorageLocation>(
902 DACtx->getStableStorageLocation(RecordPRValue));
903 return *Loc;
904 }
905
getOrCreateNullPointerValue(QualType PointeeType)906 PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
907 return DACtx->getOrCreateNullPointerValue(PointeeType);
908 }
909
initializeFieldsWithValues(RecordStorageLocation & Loc,QualType Type)910 void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
911 QualType Type) {
912 llvm::DenseSet<QualType> Visited;
913 int CreatedValuesCount = 0;
914 initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount);
915 if (CreatedValuesCount > MaxCompositeValueSize) {
916 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
917 << '\n';
918 }
919 }
920
setValue(const StorageLocation & Loc,Value & Val)921 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
922 // Records should not be associated with values.
923 assert(!isa<RecordStorageLocation>(Loc));
924 LocToVal[&Loc] = &Val;
925 }
926
setValue(const Expr & E,Value & Val)927 void Environment::setValue(const Expr &E, Value &Val) {
928 const Expr &CanonE = ignoreCFGOmittedNodes(E);
929
930 assert(CanonE.isPRValue());
931 // Records should not be associated with values.
932 assert(!CanonE.getType()->isRecordType());
933 ExprToVal[&CanonE] = &Val;
934 }
935
getValue(const StorageLocation & Loc) const936 Value *Environment::getValue(const StorageLocation &Loc) const {
937 // Records should not be associated with values.
938 assert(!isa<RecordStorageLocation>(Loc));
939 return LocToVal.lookup(&Loc);
940 }
941
getValue(const ValueDecl & D) const942 Value *Environment::getValue(const ValueDecl &D) const {
943 auto *Loc = getStorageLocation(D);
944 if (Loc == nullptr)
945 return nullptr;
946 return getValue(*Loc);
947 }
948
getValue(const Expr & E) const949 Value *Environment::getValue(const Expr &E) const {
950 // Records should not be associated with values.
951 assert(!E.getType()->isRecordType());
952
953 if (E.isPRValue()) {
954 auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
955 return It == ExprToVal.end() ? nullptr : It->second;
956 }
957
958 auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
959 if (It == ExprToLoc.end())
960 return nullptr;
961 return getValue(*It->second);
962 }
963
createValue(QualType Type)964 Value *Environment::createValue(QualType Type) {
965 llvm::DenseSet<QualType> Visited;
966 int CreatedValuesCount = 0;
967 Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
968 CreatedValuesCount);
969 if (CreatedValuesCount > MaxCompositeValueSize) {
970 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
971 << '\n';
972 }
973 return Val;
974 }
975
createValueUnlessSelfReferential(QualType Type,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)976 Value *Environment::createValueUnlessSelfReferential(
977 QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
978 int &CreatedValuesCount) {
979 assert(!Type.isNull());
980 assert(!Type->isReferenceType());
981 assert(!Type->isRecordType());
982
983 // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
984 if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
985 Depth > MaxCompositeValueDepth)
986 return nullptr;
987
988 if (Type->isBooleanType()) {
989 CreatedValuesCount++;
990 return &makeAtomicBoolValue();
991 }
992
993 if (Type->isIntegerType()) {
994 // FIXME: consider instead `return nullptr`, given that we do nothing useful
995 // with integers, and so distinguishing them serves no purpose, but could
996 // prevent convergence.
997 CreatedValuesCount++;
998 return &arena().create<IntegerValue>();
999 }
1000
1001 if (Type->isPointerType()) {
1002 CreatedValuesCount++;
1003 QualType PointeeType = Type->getPointeeType();
1004 StorageLocation &PointeeLoc =
1005 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1006
1007 return &arena().create<PointerValue>(PointeeLoc);
1008 }
1009
1010 return nullptr;
1011 }
1012
1013 StorageLocation &
createLocAndMaybeValue(QualType Ty,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)1014 Environment::createLocAndMaybeValue(QualType Ty,
1015 llvm::DenseSet<QualType> &Visited,
1016 int Depth, int &CreatedValuesCount) {
1017 if (!Visited.insert(Ty.getCanonicalType()).second)
1018 return createStorageLocation(Ty.getNonReferenceType());
1019 auto EraseVisited = llvm::make_scope_exit(
1020 [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
1021
1022 Ty = Ty.getNonReferenceType();
1023
1024 if (Ty->isRecordType()) {
1025 auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));
1026 initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);
1027 return Loc;
1028 }
1029
1030 StorageLocation &Loc = createStorageLocation(Ty);
1031
1032 if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1033 CreatedValuesCount))
1034 setValue(Loc, *Val);
1035
1036 return Loc;
1037 }
1038
initializeFieldsWithValues(RecordStorageLocation & Loc,QualType Type,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)1039 void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
1040 QualType Type,
1041 llvm::DenseSet<QualType> &Visited,
1042 int Depth,
1043 int &CreatedValuesCount) {
1044 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1045 if (FieldType->isRecordType()) {
1046 auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1047 initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),
1048 Visited, Depth + 1, CreatedValuesCount);
1049 } else {
1050 if (getValue(FieldLoc) != nullptr)
1051 return;
1052 if (!Visited.insert(FieldType.getCanonicalType()).second)
1053 return;
1054 if (Value *Val = createValueUnlessSelfReferential(
1055 FieldType, Visited, Depth + 1, CreatedValuesCount))
1056 setValue(FieldLoc, *Val);
1057 Visited.erase(FieldType.getCanonicalType());
1058 }
1059 };
1060
1061 for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
1062 assert(Field != nullptr);
1063 QualType FieldType = Field->getType();
1064
1065 if (FieldType->isReferenceType()) {
1066 Loc.setChild(*Field,
1067 &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1068 CreatedValuesCount));
1069 } else {
1070 StorageLocation *FieldLoc = Loc.getChild(*Field);
1071 assert(FieldLoc != nullptr);
1072 initField(FieldType, *FieldLoc);
1073 }
1074 }
1075 for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {
1076 // Synthetic fields cannot have reference type, so we don't need to deal
1077 // with this case.
1078 assert(!FieldType->isReferenceType());
1079 initField(FieldType, Loc.getSyntheticField(FieldName));
1080 }
1081 }
1082
createObjectInternal(const ValueDecl * D,QualType Ty,const Expr * InitExpr)1083 StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
1084 QualType Ty,
1085 const Expr *InitExpr) {
1086 if (Ty->isReferenceType()) {
1087 // Although variables of reference type always need to be initialized, it
1088 // can happen that we can't see the initializer, so `InitExpr` may still
1089 // be null.
1090 if (InitExpr) {
1091 if (auto *InitExprLoc = getStorageLocation(*InitExpr))
1092 return *InitExprLoc;
1093 }
1094
1095 // Even though we have an initializer, we might not get an
1096 // InitExprLoc, for example if the InitExpr is a CallExpr for which we
1097 // don't have a function body. In this case, we just invent a storage
1098 // location and value -- it's the best we can do.
1099 return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
1100 }
1101
1102 StorageLocation &Loc =
1103 D ? createStorageLocation(*D) : createStorageLocation(Ty);
1104
1105 if (Ty->isRecordType()) {
1106 auto &RecordLoc = cast<RecordStorageLocation>(Loc);
1107 if (!InitExpr)
1108 initializeFieldsWithValues(RecordLoc);
1109 } else {
1110 Value *Val = nullptr;
1111 if (InitExpr)
1112 // In the (few) cases where an expression is intentionally
1113 // "uninterpreted", `InitExpr` is not associated with a value. There are
1114 // two ways to handle this situation: propagate the status, so that
1115 // uninterpreted initializers result in uninterpreted variables, or
1116 // provide a default value. We choose the latter so that later refinements
1117 // of the variable can be used for reasoning about the surrounding code.
1118 // For this reason, we let this case be handled by the `createValue()`
1119 // call below.
1120 //
1121 // FIXME. If and when we interpret all language cases, change this to
1122 // assert that `InitExpr` is interpreted, rather than supplying a
1123 // default value (assuming we don't update the environment API to return
1124 // references).
1125 Val = getValue(*InitExpr);
1126 if (!Val)
1127 Val = createValue(Ty);
1128 if (Val)
1129 setValue(Loc, *Val);
1130 }
1131
1132 return Loc;
1133 }
1134
assume(const Formula & F)1135 void Environment::assume(const Formula &F) {
1136 DACtx->addFlowConditionConstraint(FlowConditionToken, F);
1137 }
1138
proves(const Formula & F) const1139 bool Environment::proves(const Formula &F) const {
1140 return DACtx->flowConditionImplies(FlowConditionToken, F);
1141 }
1142
allows(const Formula & F) const1143 bool Environment::allows(const Formula &F) const {
1144 return DACtx->flowConditionAllows(FlowConditionToken, F);
1145 }
1146
dump(raw_ostream & OS) const1147 void Environment::dump(raw_ostream &OS) const {
1148 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1149 if (LocForRecordReturnVal != nullptr)
1150 LocToName[LocForRecordReturnVal] = "(returned record)";
1151 if (ThisPointeeLoc != nullptr)
1152 LocToName[ThisPointeeLoc] = "this";
1153
1154 OS << "DeclToLoc:\n";
1155 for (auto [D, L] : DeclToLoc) {
1156 auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1157 OS << " [" << Iter->second << ", " << L << "]\n";
1158 }
1159 OS << "ExprToLoc:\n";
1160 for (auto [E, L] : ExprToLoc)
1161 OS << " [" << E << ", " << L << "]\n";
1162
1163 OS << "ExprToVal:\n";
1164 for (auto [E, V] : ExprToVal)
1165 OS << " [" << E << ", " << V << ": " << *V << "]\n";
1166
1167 OS << "LocToVal:\n";
1168 for (auto [L, V] : LocToVal) {
1169 OS << " [" << L;
1170 if (auto Iter = LocToName.find(L); Iter != LocToName.end())
1171 OS << " (" << Iter->second << ")";
1172 OS << ", " << V << ": " << *V << "]\n";
1173 }
1174
1175 if (const FunctionDecl *Func = getCurrentFunc()) {
1176 if (Func->getReturnType()->isReferenceType()) {
1177 OS << "ReturnLoc: " << ReturnLoc;
1178 if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1179 OS << " (" << Iter->second << ")";
1180 OS << "\n";
1181 } else if (Func->getReturnType()->isRecordType() ||
1182 isa<CXXConstructorDecl>(Func)) {
1183 OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";
1184 } else if (!Func->getReturnType()->isVoidType()) {
1185 if (ReturnVal == nullptr)
1186 OS << "ReturnVal: nullptr\n";
1187 else
1188 OS << "ReturnVal: " << *ReturnVal << "\n";
1189 }
1190
1191 if (isa<CXXMethodDecl>(Func)) {
1192 OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";
1193 }
1194 }
1195
1196 OS << "\n";
1197 DACtx->dumpFlowCondition(FlowConditionToken, OS);
1198 }
1199
dump() const1200 void Environment::dump() const { dump(llvm::dbgs()); }
1201
buildResultObjectMap(DataflowAnalysisContext * DACtx,const FunctionDecl * FuncDecl,RecordStorageLocation * ThisPointeeLoc,RecordStorageLocation * LocForRecordReturnVal)1202 Environment::PrValueToResultObject Environment::buildResultObjectMap(
1203 DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl,
1204 RecordStorageLocation *ThisPointeeLoc,
1205 RecordStorageLocation *LocForRecordReturnVal) {
1206 assert(FuncDecl->doesThisDeclarationHaveABody());
1207
1208 PrValueToResultObject Map = buildResultObjectMap(
1209 DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1210
1211 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1212 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1213 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1214
1215 return Map;
1216 }
1217
buildResultObjectMap(DataflowAnalysisContext * DACtx,Stmt * S,RecordStorageLocation * ThisPointeeLoc,RecordStorageLocation * LocForRecordReturnVal)1218 Environment::PrValueToResultObject Environment::buildResultObjectMap(
1219 DataflowAnalysisContext *DACtx, Stmt *S,
1220 RecordStorageLocation *ThisPointeeLoc,
1221 RecordStorageLocation *LocForRecordReturnVal) {
1222 PrValueToResultObject Map;
1223 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1224 Visitor.TraverseStmt(S);
1225 return Map;
1226 }
1227
getImplicitObjectLocation(const CXXMemberCallExpr & MCE,const Environment & Env)1228 RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
1229 const Environment &Env) {
1230 Expr *ImplicitObject = MCE.getImplicitObjectArgument();
1231 if (ImplicitObject == nullptr)
1232 return nullptr;
1233 if (ImplicitObject->getType()->isPointerType()) {
1234 if (auto *Val = Env.get<PointerValue>(*ImplicitObject))
1235 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
1236 return nullptr;
1237 }
1238 return cast_or_null<RecordStorageLocation>(
1239 Env.getStorageLocation(*ImplicitObject));
1240 }
1241
getBaseObjectLocation(const MemberExpr & ME,const Environment & Env)1242 RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
1243 const Environment &Env) {
1244 Expr *Base = ME.getBase();
1245 if (Base == nullptr)
1246 return nullptr;
1247 if (ME.isArrow()) {
1248 if (auto *Val = Env.get<PointerValue>(*Base))
1249 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
1250 return nullptr;
1251 }
1252 return Env.get<RecordStorageLocation>(*Base);
1253 }
1254
1255 } // namespace dataflow
1256 } // namespace clang
1257