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