• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
22 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
23 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
24 #include "clang/Analysis/FlowSensitive/Formula.h"
25 #include "clang/Analysis/FlowSensitive/Logger.h"
26 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
27 #include "clang/Analysis/FlowSensitive/Value.h"
28 #include "llvm/ADT/DenseMap.h"
29 #include "llvm/ADT/DenseSet.h"
30 #include "llvm/ADT/MapVector.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include <memory>
34 #include <type_traits>
35 #include <utility>
36 
37 namespace clang {
38 namespace dataflow {
39 
40 /// Indicates the result of a tentative comparison.
41 enum class ComparisonResult {
42   Same,
43   Different,
44   Unknown,
45 };
46 
47 /// The result of a `widen` operation.
48 struct WidenResult {
49   /// Non-null pointer to a potentially widened version of the input value.
50   Value *V;
51   /// Whether `V` represents a "change" (that is, a different value) with
52   /// respect to the previous value in the sequence.
53   LatticeEffect Effect;
54 };
55 
56 /// Holds the state of the program (store and heap) at a given program point.
57 ///
58 /// WARNING: Symbolic values that are created by the environment for static
59 /// local and global variables are not currently invalidated on function calls.
60 /// This is unsound and should be taken into account when designing dataflow
61 /// analyses.
62 class Environment {
63 public:
64   /// Supplements `Environment` with non-standard comparison and join
65   /// operations.
66   class ValueModel {
67   public:
68     virtual ~ValueModel() = default;
69 
70     /// Returns:
71     ///   `Same`: `Val1` is equivalent to `Val2`, according to the model.
72     ///   `Different`: `Val1` is distinct from `Val2`, according to the model.
73     ///   `Unknown`: The model can't determine a relationship between `Val1` and
74     ///    `Val2`.
75     ///
76     /// Requirements:
77     ///
78     ///  `Val1` and `Val2` must be distinct.
79     ///
80     ///  `Val1` and `Val2` must model values of type `Type`.
81     ///
82     ///  `Val1` and `Val2` must be assigned to the same storage location in
83     ///  `Env1` and `Env2` respectively.
compare(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2)84     virtual ComparisonResult compare(QualType Type, const Value &Val1,
85                                      const Environment &Env1, const Value &Val2,
86                                      const Environment &Env2) {
87       // FIXME: Consider adding `QualType` to `Value` and removing the `Type`
88       // argument here.
89       return ComparisonResult::Unknown;
90     }
91 
92     /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
93     /// obey the properties of a lattice join.
94     ///
95     /// `Env1` and `Env2` can be used to query child values and path condition
96     /// implications of `Val1` and `Val2` respectively.
97     ///
98     /// Requirements:
99     ///
100     ///  `Val1` and `Val2` must be distinct.
101     ///
102     ///  `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`.
103     ///
104     ///  `Val1` and `Val2` must be assigned to the same storage location in
105     ///  `Env1` and `Env2` respectively.
join(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2,Value & JoinedVal,Environment & JoinedEnv)106     virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
107                       const Value &Val2, const Environment &Env2,
108                       Value &JoinedVal, Environment &JoinedEnv) {}
109 
110     /// This function may widen the current value -- replace it with an
111     /// approximation that can reach a fixed point more quickly than iterated
112     /// application of the transfer function alone. The previous value is
113     /// provided to inform the choice of widened value. The function must also
114     /// serve as a comparison operation, by indicating whether the widened value
115     /// is equivalent to the previous value.
116     ///
117     /// Returns one of the folowing:
118     /// *  `std::nullopt`, if this value is not of interest to the
119     ///     model.
120     /// *  A `WidenResult` with:
121     ///    *  A non-null `Value *` that points either to `Current` or a widened
122     ///       version of `Current`. This value must be consistent with
123     ///       the flow condition of `CurrentEnv`. We particularly caution
124     ///       against using `Prev`, which is rarely consistent.
125     ///    *  A `LatticeEffect` indicating whether the value should be
126     ///       considered a new value (`Changed`) or one *equivalent* (if not
127     ///       necessarily equal) to `Prev` (`Unchanged`).
128     ///
129     /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
130     /// condition implications of `Prev` and `Current`, respectively.
131     ///
132     /// Requirements:
133     ///
134     ///  `Prev` and `Current` must model values of type `Type`.
135     ///
136     ///  `Prev` and `Current` must be assigned to the same storage location in
137     ///  `PrevEnv` and `CurrentEnv`, respectively.
widen(QualType Type,Value & Prev,const Environment & PrevEnv,Value & Current,Environment & CurrentEnv)138     virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
139                                              const Environment &PrevEnv,
140                                              Value &Current,
141                                              Environment &CurrentEnv) {
142       // The default implementation reduces to just comparison, since comparison
143       // is required by the API, even if no widening is performed.
144       switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
145       case ComparisonResult::Unknown:
146         return std::nullopt;
147       case ComparisonResult::Same:
148         return WidenResult{&Current, LatticeEffect::Unchanged};
149       case ComparisonResult::Different:
150         return WidenResult{&Current, LatticeEffect::Changed};
151       }
152       llvm_unreachable("all cases in switch covered");
153     }
154   };
155 
156   /// Creates an environment that uses `DACtx` to store objects that encompass
157   /// the state of a program.
158   explicit Environment(DataflowAnalysisContext &DACtx);
159 
160   // Copy-constructor is private, Environments should not be copied. See fork().
161   Environment &operator=(const Environment &Other) = delete;
162 
163   Environment(Environment &&Other) = default;
164   Environment &operator=(Environment &&Other) = default;
165 
166   /// Creates an environment that uses `DACtx` to store objects that encompass
167   /// the state of a program.
168   ///
169   /// If `DeclCtx` is a function, initializes the environment with symbolic
170   /// representations of the function parameters.
171   ///
172   /// If `DeclCtx` is a non-static member function, initializes the environment
173   /// with a symbolic representation of the `this` pointee.
174   Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
175 
176   /// Assigns storage locations and values to all parameters, captures, global
177   /// variables, fields and functions referenced in the function currently being
178   /// analyzed.
179   ///
180   /// Requirements:
181   ///
182   ///  The function must have a body, i.e.
183   ///  `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
184   void initialize();
185 
186   /// Returns a new environment that is a copy of this one.
187   ///
188   /// The state of the program is initially the same, but can be mutated without
189   /// affecting the original.
190   ///
191   /// However the original should not be further mutated, as this may interfere
192   /// with the fork. (In practice, values are stored independently, but the
193   /// forked flow condition references the original).
194   Environment fork() const;
195 
196   /// Creates and returns an environment to use for an inline analysis  of the
197   /// callee. Uses the storage location from each argument in the `Call` as the
198   /// storage location for the corresponding parameter in the callee.
199   ///
200   /// Requirements:
201   ///
202   ///  The callee of `Call` must be a `FunctionDecl`.
203   ///
204   ///  The body of the callee must not reference globals.
205   ///
206   ///  The arguments of `Call` must map 1:1 to the callee's parameters.
207   Environment pushCall(const CallExpr *Call) const;
208   Environment pushCall(const CXXConstructExpr *Call) const;
209 
210   /// Moves gathered information back into `this` from a `CalleeEnv` created via
211   /// `pushCall`.
212   void popCall(const CallExpr *Call, const Environment &CalleeEnv);
213   void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
214 
215   /// Returns true if and only if the environment is equivalent to `Other`, i.e
216   /// the two environments:
217   ///  - have the same mappings from declarations to storage locations,
218   ///  - have the same mappings from expressions to storage locations,
219   ///  - have the same or equivalent (according to `Model`) values assigned to
220   ///    the same storage locations.
221   ///
222   /// Requirements:
223   ///
224   ///  `Other` and `this` must use the same `DataflowAnalysisContext`.
225   bool equivalentTo(const Environment &Other,
226                     Environment::ValueModel &Model) const;
227 
228   /// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join.
229   /// If the join happens within a full expression, expression state should be
230   /// kept; otherwise, we can discard it.
231   enum ExprJoinBehavior {
232     DiscardExprState,
233     KeepExprState,
234   };
235 
236   /// Joins two environments by taking the intersection of storage locations and
237   /// values that are stored in them. Distinct values that are assigned to the
238   /// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
239   ///
240   /// Requirements:
241   ///
242   ///  `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
243   static Environment join(const Environment &EnvA, const Environment &EnvB,
244                           Environment::ValueModel &Model,
245                           ExprJoinBehavior ExprBehavior);
246 
247   /// Returns a value that approximates both `Val1` and `Val2`, or null if no
248   /// such value can be produced.
249   ///
250   /// `Env1` and `Env2` can be used to query child values and path condition
251   /// implications of `Val1` and `Val2` respectively. The joined value will be
252   /// produced in `JoinedEnv`.
253   ///
254   /// Requirements:
255   ///
256   ///  `Val1` and `Val2` must model values of type `Type`.
257   static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1,
258                            Value *Val2, const Environment &Env2,
259                            Environment &JoinedEnv,
260                            Environment::ValueModel &Model);
261 
262   /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
263   /// approximation.
264   ///
265   /// Requirements:
266   ///
267   ///  `PrevEnv` must be the immediate previous version of the environment.
268   ///  `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
269   LatticeEffect widen(const Environment &PrevEnv,
270                       Environment::ValueModel &Model);
271 
272   // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
273   // `getStableStorageLocation`, or something more appropriate.
274 
275   /// Creates a storage location appropriate for `Type`. Does not assign a value
276   /// to the returned storage location in the environment.
277   ///
278   /// Requirements:
279   ///
280   ///  `Type` must not be null.
281   StorageLocation &createStorageLocation(QualType Type);
282 
283   /// Creates a storage location for `D`. Does not assign the returned storage
284   /// location to `D` in the environment. Does not assign a value to the
285   /// returned storage location in the environment.
286   StorageLocation &createStorageLocation(const ValueDecl &D);
287 
288   /// Creates a storage location for `E`. Does not assign the returned storage
289   /// location to `E` in the environment. Does not assign a value to the
290   /// returned storage location in the environment.
291   StorageLocation &createStorageLocation(const Expr &E);
292 
293   /// Assigns `Loc` as the storage location of `D` in the environment.
294   ///
295   /// Requirements:
296   ///
297   ///  `D` must not already have a storage location in the environment.
298   void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
299 
300   /// Returns the storage location assigned to `D` in the environment, or null
301   /// if `D` isn't assigned a storage location in the environment.
302   StorageLocation *getStorageLocation(const ValueDecl &D) const;
303 
304   /// Removes the location assigned to `D` in the environment (if any).
305   void removeDecl(const ValueDecl &D);
306 
307   /// Assigns `Loc` as the storage location of the glvalue `E` in the
308   /// environment.
309   ///
310   /// Requirements:
311   ///
312   ///  `E` must not be assigned a storage location in the environment.
313   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
314   void setStorageLocation(const Expr &E, StorageLocation &Loc);
315 
316   /// Returns the storage location assigned to the glvalue `E` in the
317   /// environment, or null if `E` isn't assigned a storage location in the
318   /// environment.
319   ///
320   /// Requirements:
321   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
322   StorageLocation *getStorageLocation(const Expr &E) const;
323 
324   /// Returns the result of casting `getStorageLocation(...)` to a subclass of
325   /// `StorageLocation` (using `cast_or_null<T>`).
326   /// This assert-fails if the result of `getStorageLocation(...)` is not of
327   /// type `T *`; if the storage location is not guaranteed to have type `T *`,
328   /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead.
329   template <typename T>
330   std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const ValueDecl & D)331   get(const ValueDecl &D) const {
332     return cast_or_null<T>(getStorageLocation(D));
333   }
334   template <typename T>
335   std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const Expr & E)336   get(const Expr &E) const {
337     return cast_or_null<T>(getStorageLocation(E));
338   }
339 
340   /// Returns the storage location assigned to the `this` pointee in the
341   /// environment or null if the `this` pointee has no assigned storage location
342   /// in the environment.
getThisPointeeStorageLocation()343   RecordStorageLocation *getThisPointeeStorageLocation() const {
344     return ThisPointeeLoc;
345   }
346 
347   /// Sets the storage location assigned to the `this` pointee in the
348   /// environment.
setThisPointeeStorageLocation(RecordStorageLocation & Loc)349   void setThisPointeeStorageLocation(RecordStorageLocation &Loc) {
350     ThisPointeeLoc = &Loc;
351   }
352 
353   /// Returns the location of the result object for a record-type prvalue.
354   ///
355   /// In C++, prvalues of record type serve only a limited purpose: They can
356   /// only be used to initialize a result object (e.g. a variable or a
357   /// temporary). This function returns the location of that result object.
358   ///
359   /// When creating a prvalue of record type, we already need the storage
360   /// location of the result object to pass in `this`, even though prvalues are
361   /// otherwise not associated with storage locations.
362   ///
363   /// Requirements:
364   ///  `E` must be a prvalue of record type.
365   RecordStorageLocation &
366   getResultObjectLocation(const Expr &RecordPRValue) const;
367 
368   /// Returns the return value of the current function. This can be null if:
369   /// - The function has a void return type
370   /// - No return value could be determined for the function, for example
371   ///   because it calls a function without a body.
372   ///
373   /// Requirements:
374   ///  The current function must have a non-reference return type.
getReturnValue()375   Value *getReturnValue() const {
376     assert(getCurrentFunc() != nullptr &&
377            !getCurrentFunc()->getReturnType()->isReferenceType());
378     return ReturnVal;
379   }
380 
381   /// Returns the storage location for the reference returned by the current
382   /// function. This can be null if function doesn't return a single consistent
383   /// reference.
384   ///
385   /// Requirements:
386   ///  The current function must have a reference return type.
getReturnStorageLocation()387   StorageLocation *getReturnStorageLocation() const {
388     assert(getCurrentFunc() != nullptr &&
389            getCurrentFunc()->getReturnType()->isReferenceType());
390     return ReturnLoc;
391   }
392 
393   /// Sets the return value of the current function.
394   ///
395   /// Requirements:
396   ///  The current function must have a non-reference return type.
setReturnValue(Value * Val)397   void setReturnValue(Value *Val) {
398     assert(getCurrentFunc() != nullptr &&
399            !getCurrentFunc()->getReturnType()->isReferenceType());
400     ReturnVal = Val;
401   }
402 
403   /// Sets the storage location for the reference returned by the current
404   /// function.
405   ///
406   /// Requirements:
407   ///  The current function must have a reference return type.
setReturnStorageLocation(StorageLocation * Loc)408   void setReturnStorageLocation(StorageLocation *Loc) {
409     assert(getCurrentFunc() != nullptr &&
410            getCurrentFunc()->getReturnType()->isReferenceType());
411     ReturnLoc = Loc;
412   }
413 
414   /// Returns a pointer value that represents a null pointer. Calls with
415   /// `PointeeType` that are canonically equivalent will return the same result.
416   PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
417 
418   /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
419   /// returns null.
420   ///
421   /// If `Type` is a pointer or reference type, creates all the necessary
422   /// storage locations and values for indirections until it finds a
423   /// non-pointer/non-reference type.
424   ///
425   /// If `Type` is one of the following types, this function will always return
426   /// a non-null pointer:
427   /// - `bool`
428   /// - Any integer type
429   ///
430   /// Requirements:
431   ///
432   ///  - `Type` must not be null.
433   ///  - `Type` must not be a reference type or record type.
434   Value *createValue(QualType Type);
435 
436   /// Creates an object (i.e. a storage location with an associated value) of
437   /// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
438   /// initializes the object with this value. Otherwise, initializes the object
439   /// with a value created using `createValue()`.
440   StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
441     return createObjectInternal(nullptr, Ty, InitExpr);
442   }
443 
444   /// Creates an object for the variable declaration `D`. If `D` has an
445   /// initializer and this initializer is associated with a value, initializes
446   /// the object with this value.  Otherwise, initializes the object with a
447   /// value created using `createValue()`. Uses the storage location returned by
448   /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
createObject(const VarDecl & D)449   StorageLocation &createObject(const VarDecl &D) {
450     return createObjectInternal(&D, D.getType(), D.getInit());
451   }
452 
453   /// Creates an object for the variable declaration `D`. If `InitExpr` is
454   /// non-null and has a value associated with it, initializes the object with
455   /// this value. Otherwise, initializes the object with a value created using
456   /// `createValue()`.  Uses the storage location returned by
457   /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
createObject(const ValueDecl & D,const Expr * InitExpr)458   StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) {
459     return createObjectInternal(&D, D.getType(), InitExpr);
460   }
461 
462   /// Initializes the fields (including synthetic fields) of `Loc` with values,
463   /// unless values of the field type are not supported or we hit one of the
464   /// limits at which we stop producing values.
465   /// If a field already has a value, that value is preserved.
466   /// If `Type` is provided, initializes only those fields that are modeled for
467   /// `Type`; this is intended for use in cases where `Loc` is a derived type
468   /// and we only want to initialize the fields of a base type.
469   void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type);
initializeFieldsWithValues(RecordStorageLocation & Loc)470   void initializeFieldsWithValues(RecordStorageLocation &Loc) {
471     initializeFieldsWithValues(Loc, Loc.getType());
472   }
473 
474   /// Assigns `Val` as the value of `Loc` in the environment.
475   ///
476   /// Requirements:
477   ///
478   ///  `Loc` must not be a `RecordStorageLocation`.
479   void setValue(const StorageLocation &Loc, Value &Val);
480 
481   /// Clears any association between `Loc` and a value in the environment.
clearValue(const StorageLocation & Loc)482   void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); }
483 
484   /// Assigns `Val` as the value of the prvalue `E` in the environment.
485   ///
486   /// Requirements:
487   ///
488   ///  - `E` must be a prvalue.
489   ///  - `E` must not have record type.
490   void setValue(const Expr &E, Value &Val);
491 
492   /// Returns the value assigned to `Loc` in the environment or null if `Loc`
493   /// isn't assigned a value in the environment.
494   ///
495   /// Requirements:
496   ///
497   ///  `Loc` must not be a `RecordStorageLocation`.
498   Value *getValue(const StorageLocation &Loc) const;
499 
500   /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
501   /// storage location in the environment, otherwise returns null.
502   ///
503   /// Requirements:
504   ///
505   ///  `D` must not have record type.
506   Value *getValue(const ValueDecl &D) const;
507 
508   /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
509   /// storage location in the environment, otherwise returns null.
510   Value *getValue(const Expr &E) const;
511 
512   /// Returns the result of casting `getValue(...)` to a subclass of `Value`
513   /// (using `cast_or_null<T>`).
514   /// This assert-fails if the result of `getValue(...)` is not of type `T *`;
515   /// if the value is not guaranteed to have type `T *`, consider using
516   /// `dyn_cast_or_null<T>(getValue(...))` instead.
517   template <typename T>
518   std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const StorageLocation & Loc)519   get(const StorageLocation &Loc) const {
520     return cast_or_null<T>(getValue(Loc));
521   }
522   template <typename T>
523   std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const ValueDecl & D)524   get(const ValueDecl &D) const {
525     return cast_or_null<T>(getValue(D));
526   }
527   template <typename T>
get(const Expr & E)528   std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const {
529     return cast_or_null<T>(getValue(E));
530   }
531 
532   // FIXME: should we deprecate the following & call arena().create() directly?
533 
534   /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
535   /// constructor, and returns a reference to it.
536   ///
537   /// The analysis context takes ownership of the created object. The object
538   /// will be destroyed when the analysis context is destroyed.
539   template <typename T, typename... Args>
540   std::enable_if_t<std::is_base_of<Value, T>::value, T &>
create(Args &&...args)541   create(Args &&...args) {
542     return arena().create<T>(std::forward<Args>(args)...);
543   }
544 
545   /// Returns a symbolic integer value that models an integer literal equal to
546   /// `Value`
getIntLiteralValue(llvm::APInt Value)547   IntegerValue &getIntLiteralValue(llvm::APInt Value) const {
548     return arena().makeIntLiteral(Value);
549   }
550 
551   /// Returns a symbolic boolean value that models a boolean literal equal to
552   /// `Value`
getBoolLiteralValue(bool Value)553   BoolValue &getBoolLiteralValue(bool Value) const {
554     return arena().makeBoolValue(arena().makeLiteral(Value));
555   }
556 
557   /// Returns an atomic boolean value.
makeAtomicBoolValue()558   BoolValue &makeAtomicBoolValue() const {
559     return arena().makeAtomValue();
560   }
561 
562   /// Returns a unique instance of boolean Top.
makeTopBoolValue()563   BoolValue &makeTopBoolValue() const {
564     return arena().makeTopValue();
565   }
566 
567   /// Returns a boolean value that represents the conjunction of `LHS` and
568   /// `RHS`. Subsequent calls with the same arguments, regardless of their
569   /// order, will return the same result. If the given boolean values represent
570   /// the same value, the result will be the value itself.
makeAnd(BoolValue & LHS,BoolValue & RHS)571   BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
572     return arena().makeBoolValue(
573         arena().makeAnd(LHS.formula(), RHS.formula()));
574   }
575 
576   /// Returns a boolean value that represents the disjunction of `LHS` and
577   /// `RHS`. Subsequent calls with the same arguments, regardless of their
578   /// order, will return the same result. If the given boolean values represent
579   /// the same value, the result will be the value itself.
makeOr(BoolValue & LHS,BoolValue & RHS)580   BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
581     return arena().makeBoolValue(
582         arena().makeOr(LHS.formula(), RHS.formula()));
583   }
584 
585   /// Returns a boolean value that represents the negation of `Val`. Subsequent
586   /// calls with the same argument will return the same result.
makeNot(BoolValue & Val)587   BoolValue &makeNot(BoolValue &Val) const {
588     return arena().makeBoolValue(arena().makeNot(Val.formula()));
589   }
590 
591   /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
592   /// the same arguments, will return the same result. If the given boolean
593   /// values represent the same value, the result will be a value that
594   /// represents the true boolean literal.
makeImplication(BoolValue & LHS,BoolValue & RHS)595   BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
596     return arena().makeBoolValue(
597         arena().makeImplies(LHS.formula(), RHS.formula()));
598   }
599 
600   /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
601   /// the same arguments, regardless of their order, will return the same
602   /// result. If the given boolean values represent the same value, the result
603   /// will be a value that represents the true boolean literal.
makeIff(BoolValue & LHS,BoolValue & RHS)604   BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
605     return arena().makeBoolValue(
606         arena().makeEquals(LHS.formula(), RHS.formula()));
607   }
608 
609   /// Returns a boolean variable that identifies the flow condition (FC).
610   ///
611   /// The flow condition is a set of facts that are necessarily true when the
612   /// program reaches the current point, expressed as boolean formulas.
613   /// The flow condition token is equivalent to the AND of these facts.
614   ///
615   /// These may e.g. constrain the value of certain variables. A pointer
616   /// variable may have a consistent modeled PointerValue throughout, but at a
617   /// given point the Environment may tell us that the value must be non-null.
618   ///
619   /// The FC is necessary but not sufficient for this point to be reachable.
620   /// In particular, where the FC token appears in flow conditions of successor
621   /// environments, it means "point X may have been reached", not
622   /// "point X was reached".
getFlowConditionToken()623   Atom getFlowConditionToken() const { return FlowConditionToken; }
624 
625   /// Record a fact that must be true if this point in the program is reached.
626   void assume(const Formula &);
627 
628   /// Returns true if the formula is always true when this point is reached.
629   /// Returns false if the formula may be false (or the flow condition isn't
630   /// sufficiently precise to prove that it is true) or if the solver times out.
631   ///
632   /// Note that there is an asymmetry between this function and `allows()` in
633   /// that they both return false if the solver times out. The assumption is
634   /// that if `proves()` or `allows()` returns true, this will result in a
635   /// diagnostic, and we want to bias towards false negatives in the case where
636   /// the solver times out.
637   bool proves(const Formula &) const;
638 
639   /// Returns true if the formula may be true when this point is reached.
640   /// Returns false if the formula is always false when this point is reached
641   /// (or the flow condition is overly constraining) or if the solver times out.
642   bool allows(const Formula &) const;
643 
644   /// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
645   /// returns null.
getDeclCtx()646   const DeclContext *getDeclCtx() const { return CallStack.back(); }
647 
648   /// Returns the function currently being analyzed, or null if the code being
649   /// analyzed isn't part of a function.
getCurrentFunc()650   const FunctionDecl *getCurrentFunc() const {
651     return dyn_cast<FunctionDecl>(getDeclCtx());
652   }
653 
654   /// Returns the size of the call stack.
callStackSize()655   size_t callStackSize() const { return CallStack.size(); }
656 
657   /// Returns whether this `Environment` can be extended to analyze the given
658   /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
659   /// given `MaxDepth`.
660   bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
661 
662   /// Returns the `DataflowAnalysisContext` used by the environment.
getDataflowAnalysisContext()663   DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
664 
arena()665   Arena &arena() const { return DACtx->arena(); }
666 
667   LLVM_DUMP_METHOD void dump() const;
668   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
669 
670 private:
671   using PrValueToResultObject =
672       llvm::DenseMap<const Expr *, RecordStorageLocation *>;
673 
674   // The copy-constructor is for use in fork() only.
675   Environment(const Environment &) = default;
676 
677   /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
678   /// return null.
679   ///
680   /// Recursively initializes storage locations and values until it sees a
681   /// self-referential pointer or reference type. `Visited` is used to track
682   /// which types appeared in the reference/pointer chain in order to avoid
683   /// creating a cyclic dependency with self-referential pointers/references.
684   ///
685   /// Requirements:
686   ///
687   ///  `Type` must not be null.
688   Value *createValueUnlessSelfReferential(QualType Type,
689                                           llvm::DenseSet<QualType> &Visited,
690                                           int Depth, int &CreatedValuesCount);
691 
692   /// Creates a storage location for `Ty`. Also creates and associates a value
693   /// with the storage location, unless values of this type are not supported or
694   /// we hit one of the limits at which we stop producing values (controlled by
695   /// `Visited`, `Depth`, and `CreatedValuesCount`).
696   StorageLocation &createLocAndMaybeValue(QualType Ty,
697                                           llvm::DenseSet<QualType> &Visited,
698                                           int Depth, int &CreatedValuesCount);
699 
700   /// Initializes the fields (including synthetic fields) of `Loc` with values,
701   /// unless values of the field type are not supported or we hit one of the
702   /// limits at which we stop producing values (controlled by `Visited`,
703   /// `Depth`, and `CreatedValuesCount`). If `Type` is different from
704   /// `Loc.getType()`, initializes only those fields that are modeled for
705   /// `Type`.
706   void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type,
707                                   llvm::DenseSet<QualType> &Visited, int Depth,
708                                   int &CreatedValuesCount);
709 
710   /// Shared implementation of `createObject()` overloads.
711   /// `D` and `InitExpr` may be null.
712   StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
713                                         const Expr *InitExpr);
714 
715   /// Shared implementation of `pushCall` overloads. Note that unlike
716   /// `pushCall`, this member is invoked on the environment of the callee, not
717   /// of the caller.
718   void pushCallInternal(const FunctionDecl *FuncDecl,
719                         ArrayRef<const Expr *> Args);
720 
721   /// Assigns storage locations and values to all global variables, fields
722   /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
723   void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
724 
725   static PrValueToResultObject
726   buildResultObjectMap(DataflowAnalysisContext *DACtx,
727                        const FunctionDecl *FuncDecl,
728                        RecordStorageLocation *ThisPointeeLoc,
729                        RecordStorageLocation *LocForRecordReturnVal);
730 
731   // `DACtx` is not null and not owned by this object.
732   DataflowAnalysisContext *DACtx;
733 
734   // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`,
735   // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object,
736   // shared between environments in the same call.
737   // https://github.com/llvm/llvm-project/issues/59005
738 
739   // `DeclContext` of the block being analysed if provided.
740   std::vector<const DeclContext *> CallStack;
741 
742   // Maps from prvalues of record type to their result objects. Shared between
743   // all environments for the same function.
744   // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
745   // here, though the cost is acceptable: The overhead of a `shared_ptr` is
746   // incurred when it is copied, and this happens only relatively rarely (when
747   // we fork the environment). The need for a `shared_ptr` will go away once we
748   // introduce a shared call-context object (see above).
749   std::shared_ptr<PrValueToResultObject> ResultObjectMap;
750 
751   // The following three member variables handle various different types of
752   // return values.
753   // - If the return type is not a reference and not a record: Value returned
754   //   by the function.
755   Value *ReturnVal = nullptr;
756   // - If the return type is a reference: Storage location of the reference
757   //   returned by the function.
758   StorageLocation *ReturnLoc = nullptr;
759   // - If the return type is a record or the function being analyzed is a
760   //   constructor: Storage location into which the return value should be
761   //   constructed.
762   RecordStorageLocation *LocForRecordReturnVal = nullptr;
763 
764   // The storage location of the `this` pointee. Should only be null if the
765   // function being analyzed is only a function and not a method.
766   RecordStorageLocation *ThisPointeeLoc = nullptr;
767 
768   // Maps from declarations and glvalue expression to storage locations that are
769   // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
770   // include only storage locations that are in scope for a particular basic
771   // block.
772   llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
773   llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
774   // Maps from prvalue expressions and storage locations to the values that
775   // are assigned to them.
776   // We preserve insertion order so that join/widen process values in
777   // deterministic sequence. This in turn produces deterministic SAT formulas.
778   llvm::MapVector<const Expr *, Value *> ExprToVal;
779   llvm::MapVector<const StorageLocation *, Value *> LocToVal;
780 
781   Atom FlowConditionToken;
782 };
783 
784 /// Returns the storage location for the implicit object of a
785 /// `CXXMemberCallExpr`, or null if none is defined in the environment.
786 /// Dereferences the pointer if the member call expression was written using
787 /// `->`.
788 RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
789                                                  const Environment &Env);
790 
791 /// Returns the storage location for the base object of a `MemberExpr`, or null
792 /// if none is defined in the environment. Dereferences the pointer if the
793 /// member expression was written using `->`.
794 RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
795                                              const Environment &Env);
796 
797 } // namespace dataflow
798 } // namespace clang
799 
800 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
801