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