clang 18.0.0git
DataflowEnvironment.h
Go to the documentation of this file.
1//===-- DataflowEnvironment.h -----------------------------------*- 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#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
16#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
17
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclBase.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/Type.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/DenseSet.h"
31#include "llvm/ADT/MapVector.h"
32#include "llvm/Support/Compiler.h"
33#include "llvm/Support/ErrorHandling.h"
34#include <memory>
35#include <type_traits>
36#include <utility>
37
38namespace clang {
39namespace dataflow {
40
41/// Indicates the result of a tentative comparison.
42enum class ComparisonResult {
43 Same,
45 Unknown,
46};
47
48/// Holds the state of the program (store and heap) at a given program point.
49///
50/// WARNING: Symbolic values that are created by the environment for static
51/// local and global variables are not currently invalidated on function calls.
52/// This is unsound and should be taken into account when designing dataflow
53/// analyses.
55public:
56 /// Supplements `Environment` with non-standard comparison and join
57 /// operations.
58 class ValueModel {
59 public:
60 virtual ~ValueModel() = default;
61
62 /// Returns:
63 /// `Same`: `Val1` is equivalent to `Val2`, according to the model.
64 /// `Different`: `Val1` is distinct from `Val2`, according to the model.
65 /// `Unknown`: The model can't determine a relationship between `Val1` and
66 /// `Val2`.
67 ///
68 /// Requirements:
69 ///
70 /// `Val1` and `Val2` must be distinct.
71 ///
72 /// `Val1` and `Val2` must model values of type `Type`.
73 ///
74 /// `Val1` and `Val2` must be assigned to the same storage location in
75 /// `Env1` and `Env2` respectively.
77 const Environment &Env1, const Value &Val2,
78 const Environment &Env2) {
79 // FIXME: Consider adding QualType to RecordValue and removing the Type
80 // argument here.
82 }
83
84 /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could
85 /// be a strict lattice join or a more general widening operation.
86 ///
87 /// If this function returns true, `MergedVal` will be assigned to a storage
88 /// location of type `Type` in `MergedEnv`.
89 ///
90 /// `Env1` and `Env2` can be used to query child values and path condition
91 /// implications of `Val1` and `Val2` respectively.
92 ///
93 /// Requirements:
94 ///
95 /// `Val1` and `Val2` must be distinct.
96 ///
97 /// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`.
98 ///
99 /// `Val1` and `Val2` must be assigned to the same storage location in
100 /// `Env1` and `Env2` respectively.
101 virtual bool merge(QualType Type, const Value &Val1,
102 const Environment &Env1, const Value &Val2,
103 const Environment &Env2, Value &MergedVal,
104 Environment &MergedEnv) {
105 return true;
106 }
107
108 /// This function may widen the current value -- replace it with an
109 /// approximation that can reach a fixed point more quickly than iterated
110 /// application of the transfer function alone. The previous value is
111 /// provided to inform the choice of widened value. The function must also
112 /// serve as a comparison operation, by indicating whether the widened value
113 /// is equivalent to the previous value.
114 ///
115 /// Returns either:
116 ///
117 /// `nullptr`, if this value is not of interest to the model, or
118 ///
119 /// `&Prev`, if the widened value is equivalent to `Prev`, or
120 ///
121 /// A non-null value that approximates `Current`. `Prev` is available to
122 /// inform the chosen approximation.
123 ///
124 /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
125 /// condition implications of `Prev` and `Current`, respectively.
126 ///
127 /// Requirements:
128 ///
129 /// `Prev` and `Current` must model values of type `Type`.
130 ///
131 /// `Prev` and `Current` must be assigned to the same storage location in
132 /// `PrevEnv` and `CurrentEnv`, respectively.
133 virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
134 Value &Current, Environment &CurrentEnv) {
135 // The default implementation reduces to just comparison, since comparison
136 // is required by the API, even if no widening is performed.
137 switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
139 return &Prev;
141 return &Current;
143 return nullptr;
144 }
145 llvm_unreachable("all cases in switch covered");
146 }
147 };
148
149 /// Creates an environment that uses `DACtx` to store objects that encompass
150 /// the state of a program.
151 explicit Environment(DataflowAnalysisContext &DACtx);
152
153 // Copy-constructor is private, Environments should not be copied. See fork().
154 Environment &operator=(const Environment &Other) = delete;
155
156 Environment(Environment &&Other) = default;
157 Environment &operator=(Environment &&Other) = default;
158
159 /// Creates an environment that uses `DACtx` to store objects that encompass
160 /// the state of a program.
161 ///
162 /// If `DeclCtx` is a function, initializes the environment with symbolic
163 /// representations of the function parameters.
164 ///
165 /// If `DeclCtx` is a non-static member function, initializes the environment
166 /// with a symbolic representation of the `this` pointee.
167 Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
168
169 /// Returns a new environment that is a copy of this one.
170 ///
171 /// The state of the program is initially the same, but can be mutated without
172 /// affecting the original.
173 ///
174 /// However the original should not be further mutated, as this may interfere
175 /// with the fork. (In practice, values are stored independently, but the
176 /// forked flow condition references the original).
177 Environment fork() const;
178
179 /// Creates and returns an environment to use for an inline analysis of the
180 /// callee. Uses the storage location from each argument in the `Call` as the
181 /// storage location for the corresponding parameter in the callee.
182 ///
183 /// Requirements:
184 ///
185 /// The callee of `Call` must be a `FunctionDecl`.
186 ///
187 /// The body of the callee must not reference globals.
188 ///
189 /// The arguments of `Call` must map 1:1 to the callee's parameters.
190 Environment pushCall(const CallExpr *Call) const;
191 Environment pushCall(const CXXConstructExpr *Call) const;
192
193 /// Moves gathered information back into `this` from a `CalleeEnv` created via
194 /// `pushCall`.
195 void popCall(const CallExpr *Call, const Environment &CalleeEnv);
196 void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
197
198 /// Returns true if and only if the environment is equivalent to `Other`, i.e
199 /// the two environments:
200 /// - have the same mappings from declarations to storage locations,
201 /// - have the same mappings from expressions to storage locations,
202 /// - have the same or equivalent (according to `Model`) values assigned to
203 /// the same storage locations.
204 ///
205 /// Requirements:
206 ///
207 /// `Other` and `this` must use the same `DataflowAnalysisContext`.
208 bool equivalentTo(const Environment &Other,
209 Environment::ValueModel &Model) const;
210
211 /// Joins two environments by taking the intersection of storage locations and
212 /// values that are stored in them. Distinct values that are assigned to the
213 /// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
214 ///
215 /// Requirements:
216 ///
217 /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
218 static Environment join(const Environment &EnvA, const Environment &EnvB,
220
221 /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
222 /// approximation.
223 ///
224 /// Requirements:
225 ///
226 /// `PrevEnv` must be the immediate previous version of the environment.
227 /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
228 LatticeJoinEffect widen(const Environment &PrevEnv,
230
231 // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
232 // `getStableStorageLocation`, or something more appropriate.
233
234 /// Creates a storage location appropriate for `Type`. Does not assign a value
235 /// to the returned storage location in the environment.
236 ///
237 /// Requirements:
238 ///
239 /// `Type` must not be null.
241
242 /// Creates a storage location for `D`. Does not assign the returned storage
243 /// location to `D` in the environment. Does not assign a value to the
244 /// returned storage location in the environment.
246
247 /// Creates a storage location for `E`. Does not assign the returned storage
248 /// location to `E` in the environment. Does not assign a value to the
249 /// returned storage location in the environment.
251
252 /// Assigns `Loc` as the storage location of `D` in the environment.
253 ///
254 /// Requirements:
255 ///
256 /// `D` must not already have a storage location in the environment.
257 void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
258
259 /// Returns the storage location assigned to `D` in the environment, or null
260 /// if `D` isn't assigned a storage location in the environment.
262
263 /// Removes the location assigned to `D` in the environment.
264 ///
265 /// Requirements:
266 ///
267 /// `D` must have a storage location assigned in the environment.
268 void removeDecl(const ValueDecl &D);
269
270 /// Assigns `Loc` as the storage location of the glvalue `E` in the
271 /// environment.
272 ///
273 /// Requirements:
274 ///
275 /// `E` must not be assigned a storage location in the environment.
276 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
277 void setStorageLocation(const Expr &E, StorageLocation &Loc);
278
279 /// Returns the storage location assigned to the glvalue `E` in the
280 /// environment, or null if `E` isn't assigned a storage location in the
281 /// environment.
282 ///
283 /// Requirements:
284 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
285 StorageLocation *getStorageLocation(const Expr &E) const;
286
287 /// Returns the storage location assigned to the `this` pointee in the
288 /// environment or null if the `this` pointee has no assigned storage location
289 /// in the environment.
291
292 /// Returns the location of the result object for a record-type prvalue.
293 ///
294 /// In C++, prvalues of record type serve only a limited purpose: They can
295 /// only be used to initialize a result object (e.g. a variable or a
296 /// temporary). This function returns the location of that result object.
297 ///
298 /// When creating a prvalue of record type, we already need the storage
299 /// location of the result object to pass in `this`, even though prvalues are
300 /// otherwise not associated with storage locations.
301 ///
302 /// FIXME: Currently, this simply returns a stable storage location for `E`,
303 /// but this doesn't do the right thing in scenarios like the following:
304 /// ```
305 /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar);
306 /// ```
307 /// Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage
308 /// locations, when in fact their storage locations should be the same.
309 /// Eventually, we want to propagate storage locations from result objects
310 /// down to the prvalues that initialize them, similar to the way that this is
311 /// done in Clang's CodeGen.
312 ///
313 /// Requirements:
314 /// `E` must be a prvalue of record type.
316
317 /// Returns the return value of the current function. This can be null if:
318 /// - The function has a void return type
319 /// - No return value could be determined for the function, for example
320 /// because it calls a function without a body.
321 ///
322 /// Requirements:
323 /// The current function must have a non-reference return type.
325 assert(getCurrentFunc() != nullptr &&
326 !getCurrentFunc()->getReturnType()->isReferenceType());
327 return ReturnVal;
328 }
329
330 /// Returns the storage location for the reference returned by the current
331 /// function. This can be null if function doesn't return a single consistent
332 /// reference.
333 ///
334 /// Requirements:
335 /// The current function must have a reference return type.
337 assert(getCurrentFunc() != nullptr &&
338 getCurrentFunc()->getReturnType()->isReferenceType());
339 return ReturnLoc;
340 }
341
342 /// Sets the return value of the current function.
343 ///
344 /// Requirements:
345 /// The current function must have a non-reference return type.
347 assert(getCurrentFunc() != nullptr &&
348 !getCurrentFunc()->getReturnType()->isReferenceType());
349 ReturnVal = Val;
350 }
351
352 /// Sets the storage location for the reference returned by the current
353 /// function.
354 ///
355 /// Requirements:
356 /// The current function must have a reference return type.
358 assert(getCurrentFunc() != nullptr &&
359 getCurrentFunc()->getReturnType()->isReferenceType());
360 ReturnLoc = Loc;
361 }
362
363 /// Returns a pointer value that represents a null pointer. Calls with
364 /// `PointeeType` that are canonically equivalent will return the same result.
366
367 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
368 /// returns null.
369 ///
370 /// If `Type` is a pointer or reference type, creates all the necessary
371 /// storage locations and values for indirections until it finds a
372 /// non-pointer/non-reference type.
373 ///
374 /// If `Type` is a class, struct, or union type, calls `setValue()` to
375 /// associate the `RecordValue` with its storage location
376 /// (`RecordValue::getLoc()`).
377 ///
378 /// If `Type` is one of the following types, this function will always return
379 /// a non-null pointer:
380 /// - `bool`
381 /// - Any integer type
382 /// - Any class, struct, or union type
383 ///
384 /// Requirements:
385 ///
386 /// `Type` must not be null.
388
389 /// Creates an object (i.e. a storage location with an associated value) of
390 /// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
391 /// initializes the object with this value. Otherwise, initializes the object
392 /// with a value created using `createValue()`.
393 StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
394 return createObjectInternal(nullptr, Ty, InitExpr);
395 }
396
397 /// Creates an object for the variable declaration `D`. If `D` has an
398 /// initializer and this initializer is associated with a value, initializes
399 /// the object with this value. Otherwise, initializes the object with a
400 /// value created using `createValue()`. Uses the storage location returned by
401 /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
403 return createObjectInternal(&D, D.getType(), D.getInit());
404 }
405
406 /// Creates an object for the variable declaration `D`. If `InitExpr` is
407 /// non-null and has a value associated with it, initializes the object with
408 /// this value. Otherwise, initializes the object with a value created using
409 /// `createValue()`. Uses the storage location returned by
410 /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
411 StorageLocation &createObject(const VarDecl &D, const Expr *InitExpr) {
412 return createObjectInternal(&D, D.getType(), InitExpr);
413 }
414
415 /// Assigns `Val` as the value of `Loc` in the environment.
416 void setValue(const StorageLocation &Loc, Value &Val);
417
418 /// Clears any association between `Loc` and a value in the environment.
419 void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); }
420
421 /// Assigns `Val` as the value of the prvalue `E` in the environment.
422 ///
423 /// If `E` is not yet associated with a storage location, associates it with
424 /// a newly created storage location. In any case, associates the storage
425 /// location of `E` with `Val`.
426 ///
427 /// Once the migration to strict handling of value categories is complete
428 /// (see https://discourse.llvm.org/t/70086), this function will be renamed to
429 /// `setValue()`. At this point, prvalue expressions will be associated
430 /// directly with `Value`s, and the legacy behavior of associating prvalue
431 /// expressions with storage locations (as described above) will be
432 /// eliminated.
433 ///
434 /// Requirements:
435 ///
436 /// `E` must be a prvalue
437 /// If `Val` is a `RecordValue`, its `RecordStorageLocation` must be the
438 /// same as that of any `RecordValue` that has already been associated with
439 /// `E`. This is to guarantee that the result object initialized by a prvalue
440 /// `RecordValue` has a durable storage location.
441 void setValue(const Expr &E, Value &Val);
442
443 /// Returns the value assigned to `Loc` in the environment or null if `Loc`
444 /// isn't assigned a value in the environment.
445 Value *getValue(const StorageLocation &Loc) const;
446
447 /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
448 /// storage location in the environment, otherwise returns null.
449 Value *getValue(const ValueDecl &D) const;
450
451 /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
452 /// storage location in the environment, otherwise returns null.
453 Value *getValue(const Expr &E) const;
454
455 // FIXME: should we deprecate the following & call arena().create() directly?
456
457 /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
458 /// constructor, and returns a reference to it.
459 ///
460 /// The analysis context takes ownership of the created object. The object
461 /// will be destroyed when the analysis context is destroyed.
462 template <typename T, typename... Args>
463 std::enable_if_t<std::is_base_of<Value, T>::value, T &>
464 create(Args &&...args) {
465 return arena().create<T>(std::forward<Args>(args)...);
466 }
467
468 /// Returns a symbolic integer value that models an integer literal equal to
469 /// `Value`
471 return arena().makeIntLiteral(Value);
472 }
473
474 /// Returns a symbolic boolean value that models a boolean literal equal to
475 /// `Value`
477 return cast<AtomicBoolValue>(
478 arena().makeBoolValue(arena().makeLiteral(Value)));
479 }
480
481 /// Returns an atomic boolean value.
483 return arena().makeAtomValue();
484 }
485
486 /// Returns a unique instance of boolean Top.
488 return arena().makeTopValue();
489 }
490
491 /// Returns a boolean value that represents the conjunction of `LHS` and
492 /// `RHS`. Subsequent calls with the same arguments, regardless of their
493 /// order, will return the same result. If the given boolean values represent
494 /// the same value, the result will be the value itself.
496 return arena().makeBoolValue(
497 arena().makeAnd(LHS.formula(), RHS.formula()));
498 }
499
500 /// Returns a boolean value that represents the disjunction of `LHS` and
501 /// `RHS`. Subsequent calls with the same arguments, regardless of their
502 /// order, will return the same result. If the given boolean values represent
503 /// the same value, the result will be the value itself.
504 BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
505 return arena().makeBoolValue(
506 arena().makeOr(LHS.formula(), RHS.formula()));
507 }
508
509 /// Returns a boolean value that represents the negation of `Val`. Subsequent
510 /// calls with the same argument will return the same result.
512 return arena().makeBoolValue(arena().makeNot(Val.formula()));
513 }
514
515 /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
516 /// the same arguments, will return the same result. If the given boolean
517 /// values represent the same value, the result will be a value that
518 /// represents the true boolean literal.
520 return arena().makeBoolValue(
521 arena().makeImplies(LHS.formula(), RHS.formula()));
522 }
523
524 /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
525 /// the same arguments, regardless of their order, will return the same
526 /// result. If the given boolean values represent the same value, the result
527 /// will be a value that represents the true boolean literal.
529 return arena().makeBoolValue(
530 arena().makeEquals(LHS.formula(), RHS.formula()));
531 }
532
533 /// Returns a boolean variable that identifies the flow condition (FC).
534 ///
535 /// The flow condition is a set of facts that are necessarily true when the
536 /// program reaches the current point, expressed as boolean formulas.
537 /// The flow condition token is equivalent to the AND of these facts.
538 ///
539 /// These may e.g. constrain the value of certain variables. A pointer
540 /// variable may have a consistent modeled PointerValue throughout, but at a
541 /// given point the Environment may tell us that the value must be non-null.
542 ///
543 /// The FC is necessary but not sufficient for this point to be reachable.
544 /// In particular, where the FC token appears in flow conditions of successor
545 /// environments, it means "point X may have been reached", not
546 /// "point X was reached".
547 Atom getFlowConditionToken() const { return FlowConditionToken; }
548
549 /// Record a fact that must be true if this point in the program is reached.
550 void addToFlowCondition(const Formula &);
551
552 /// Returns true if the formula is always true when this point is reached.
553 /// Returns false if the formula may be false, or if the flow condition isn't
554 /// sufficiently precise to prove that it is true.
555 bool flowConditionImplies(const Formula &) const;
556
557 /// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
558 /// returns null.
559 const DeclContext *getDeclCtx() const { return CallStack.back(); }
560
561 /// Returns the function currently being analyzed, or null if the code being
562 /// analyzed isn't part of a function.
564 return dyn_cast<FunctionDecl>(getDeclCtx());
565 }
566
567 /// Returns whether this `Environment` can be extended to analyze the given
568 /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
569 /// given `MaxDepth`.
570 bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
571
572 /// Returns the `DataflowAnalysisContext` used by the environment.
574
575 Arena &arena() const { return DACtx->arena(); }
576
577 LLVM_DUMP_METHOD void dump() const;
578 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
579
580private:
581 // The copy-constructor is for use in fork() only.
582 Environment(const Environment &) = default;
583
584 /// Internal version of `setStorageLocation()` that doesn't check if the
585 /// expression is a prvalue.
586 void setStorageLocationInternal(const Expr &E, StorageLocation &Loc);
587
588 /// Internal version of `getStorageLocation()` that doesn't check if the
589 /// expression is a prvalue.
590 StorageLocation *getStorageLocationInternal(const Expr &E) const;
591
592 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
593 /// return null.
594 ///
595 /// Recursively initializes storage locations and values until it sees a
596 /// self-referential pointer or reference type. `Visited` is used to track
597 /// which types appeared in the reference/pointer chain in order to avoid
598 /// creating a cyclic dependency with self-referential pointers/references.
599 ///
600 /// Requirements:
601 ///
602 /// `Type` must not be null.
603 Value *createValueUnlessSelfReferential(QualType Type,
605 int Depth, int &CreatedValuesCount);
606
607 /// Creates a storage location for `Ty`. Also creates and associates a value
608 /// with the storage location, unless values of this type are not supported or
609 /// we hit one of the limits at which we stop producing values (controlled by
610 /// `Visited`, `Depth`, and `CreatedValuesCount`).
611 StorageLocation &createLocAndMaybeValue(QualType Ty,
613 int Depth, int &CreatedValuesCount);
614
615 /// Shared implementation of `createObject()` overloads.
616 /// `D` and `InitExpr` may be null.
617 StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty,
618 const Expr *InitExpr);
619
620 /// Shared implementation of `pushCall` overloads. Note that unlike
621 /// `pushCall`, this member is invoked on the environment of the callee, not
622 /// of the caller.
623 void pushCallInternal(const FunctionDecl *FuncDecl,
625
626 /// Assigns storage locations and values to all global variables, fields
627 /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
628 void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
629
630 // `DACtx` is not null and not owned by this object.
632
633 // FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and
634 // `ThisPointeeLoc` into a separate call-context object, shared between
635 // environments in the same call.
636 // https://github.com/llvm/llvm-project/issues/59005
637
638 // `DeclContext` of the block being analysed if provided.
639 std::vector<const DeclContext *> CallStack;
640
641 // Value returned by the function (if it has non-reference return type).
642 Value *ReturnVal = nullptr;
643 // Storage location of the reference returned by the function (if it has
644 // reference return type).
645 StorageLocation *ReturnLoc = nullptr;
646 // The storage location of the `this` pointee. Should only be null if the
647 // function being analyzed is only a function and not a method.
648 RecordStorageLocation *ThisPointeeLoc = nullptr;
649
650 // Maps from declarations and glvalue expression to storage locations that are
651 // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
652 // include only storage locations that are in scope for a particular basic
653 // block.
654 llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
655 llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
656 // Maps from prvalue expressions and storage locations to the values that
657 // are assigned to them.
658 // We preserve insertion order so that join/widen process values in
659 // deterministic sequence. This in turn produces deterministic SAT formulas.
660 llvm::MapVector<const Expr *, Value *> ExprToVal;
661 llvm::MapVector<const StorageLocation *, Value *> LocToVal;
662
663 Atom FlowConditionToken;
664};
665
666/// Returns the storage location for the implicit object of a
667/// `CXXMemberCallExpr`, or null if none is defined in the environment.
668/// Dereferences the pointer if the member call expression was written using
669/// `->`.
670RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
671 const Environment &Env);
672
673/// Returns the storage location for the base object of a `MemberExpr`, or null
674/// if none is defined in the environment. Dereferences the pointer if the
675/// member expression was written using `->`.
676RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
677 const Environment &Env);
678
679/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the
680/// order in which they appear in `InitListExpr::inits()`.
681std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);
682
683/// Associates a new `RecordValue` with `Loc` and returns the new value.
684/// It is not defined whether the field values remain the same or not.
685///
686/// This function is primarily intended for use by checks that set custom
687/// properties on `RecordValue`s to model the state of these values. Such checks
688/// should avoid modifying the properties of an existing `RecordValue` because
689/// these changes would be visible to other `Environment`s that share the same
690/// `RecordValue`. Instead, call `refreshRecordValue()`, then set the properties
691/// on the new `RecordValue` that it returns. Typical usage:
692///
693/// refreshRecordValue(Loc, Env).setProperty("my_prop", MyPropValue);
694RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
695
696/// Associates a new `RecordValue` with `Expr` and returns the new value.
697/// See also documentation for the overload above.
698RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
699
700} // namespace dataflow
701} // namespace clang
702
703#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
const Environment & Env
Definition: HTMLLogger.cpp:145
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:143
C Language Family Type Representation.
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1523
Represents a call to a member function that may be written either with member call syntax (e....
Definition: ExprCXX.h:176
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2832
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1409
This represents one expression.
Definition: Expr.h:110
Represents a function declaration or definition.
Definition: Decl.h:1919
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3195
A (possibly-)qualified type.
Definition: Type.h:736
Represents a struct/union/class.
Definition: Decl.h:4036
The base class of the type hierarchy.
Definition: Type.h:1597
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:703
QualType getType() const
Definition: Decl.h:714
Represents a variable declaration or definition.
Definition: Decl.h:915
const Expr * getInit() const
Definition: Decl.h:1327
The Arena owns the objects that model data within an analysis.
Definition: Arena.h:21
IntegerValue & makeIntLiteral(llvm::APInt Value)
Returns a symbolic integer value that models an integer literal equal to Value.
Definition: Arena.cpp:84
TopBoolValue & makeTopValue()
Creates a fresh Top boolean value.
Definition: Arena.h:74
BoolValue & makeBoolValue(const Formula &)
Creates a BoolValue wrapping a particular formula.
Definition: Arena.cpp:92
AtomicBoolValue & makeAtomValue()
Creates a fresh atom and wraps in in an AtomicBoolValue.
Definition: Arena.h:69
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of StorageLocation), forwarding args to the constructor,...
Definition: Arena.h:34
Models an atomic boolean.
Definition: Value.h:131
Models a boolean.
Definition: Value.h:92
const Formula & formula() const
Definition: Value.h:105
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
Supplements Environment with non-standard comparison and join operations.
virtual ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2)
Returns: Same: Val1 is equivalent to Val2, according to the model.
virtual Value * widen(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv)
This function may widen the current value – replace it with an approximation that can reach a fixed p...
virtual bool merge(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &MergedVal, Environment &MergedEnv)
Modifies MergedVal to approximate both Val1 and Val2.
Holds the state of the program (store and heap) at a given program point.
static Environment join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model)
Joins two environments by taking the intersection of storage locations and values that are stored in ...
void addToFlowCondition(const Formula &)
Record a fact that must be true if this point in the program is reached.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
BoolValue & makeAnd(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value that represents the conjunction of LHS and RHS.
LatticeJoinEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
RecordStorageLocation * getThisPointeeStorageLocation() const
Returns the storage location assigned to the this pointee in the environment or null if the this poin...
BoolValue & makeIff(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS <=> RHS.
Environment pushCall(const CallExpr *Call) const
Creates and returns an environment to use for an inline analysis of the callee.
void clearValue(const StorageLocation &Loc)
Clears any association between Loc and a value in the environment.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
LLVM_DUMP_METHOD void dump() const
void setReturnValue(Value *Val)
Sets the return value of the current function.
Environment(Environment &&Other)=default
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
StorageLocation & createObject(const VarDecl &D)
Creates an object for the variable declaration D.
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Value * getReturnValue() const
Returns the return value of the current function.
Environment fork() const
Returns a new environment that is a copy of this one.
void popCall(const CallExpr *Call, const Environment &CalleeEnv)
Moves gathered information back into this from a CalleeEnv created via pushCall.
bool equivalentTo(const Environment &Other, Environment::ValueModel &Model) const
Returns true if and only if the environment is equivalent to Other, i.e the two environments:
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const
Returns whether this Environment can be extended to analyze the given Callee (i.e.
Environment & operator=(const Environment &Other)=delete
const FunctionDecl * getCurrentFunc() const
Returns the function currently being analyzed, or null if the code being analyzed isn't part of a fun...
StorageLocation & createObject(QualType Ty, const Expr *InitExpr=nullptr)
Creates an object (i.e.
DataflowAnalysisContext & getDataflowAnalysisContext() const
Returns the DataflowAnalysisContext used by the environment.
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue)
Returns the location of the result object for a record-type prvalue.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void removeDecl(const ValueDecl &D)
Removes the location assigned to D in the environment.
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
IntegerValue & getIntLiteralValue(llvm::APInt Value) const
Returns a symbolic integer value that models an integer literal equal to Value
Environment & operator=(Environment &&Other)=default
Atom getFlowConditionToken() const
Returns a boolean variable that identifies the flow condition (FC).
bool flowConditionImplies(const Formula &) const
Returns true if the formula is always true when this point is reached.
BoolValue & makeNot(BoolValue &Val) const
Returns a boolean value that represents the negation of Val.
StorageLocation & createObject(const VarDecl &D, const Expr *InitExpr)
Creates an object for the variable declaration D.
const DeclContext * getDeclCtx() const
Returns the DeclContext of the block being analysed, if any.
BoolValue & makeOr(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value that represents the disjunction of LHS and RHS.
std::enable_if_t< std::is_base_of< Value, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of Value), forwarding args to the constructor, and returns a reference to ...
void setReturnStorageLocation(StorageLocation *Loc)
Sets the storage location for the reference returned by the current function.
StorageLocation * getReturnStorageLocation() const
Returns the storage location for the reference returned by the current function.
AtomicBoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
BoolValue & makeImplication(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS => RHS.
Models an integer.
Definition: Value.h:158
Models a symbolic pointer. Specifically, any value of type T*.
Definition: Value.h:168
A storage location for a record (struct, class, or union).
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition: Value.h:33
Atom
Identifies an atomic boolean variable such as "V1".
Definition: Formula.h:35
ComparisonResult
Indicates the result of a tentative comparison.
LatticeJoinEffect
Effect indicating whether a lattice join operation resulted in a new value.
RecordStorageLocation * getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env)
Returns the storage location for the implicit object of a CXXMemberCallExpr, or null if none is defin...
std::vector< FieldDecl * > getFieldsForInitListExpr(const RecordDecl *RD)
Returns the fields of RD that are initialized by an InitListExpr, in the order in which they appear i...
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
RecordValue & refreshRecordValue(RecordStorageLocation &Loc, Environment &Env)
Associates a new RecordValue with Loc and returns the new value.