14824e7fdSDimitry Andric //===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===// 24824e7fdSDimitry Andric // 34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64824e7fdSDimitry Andric // 74824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 84824e7fdSDimitry Andric // 94824e7fdSDimitry Andric // This file defines an Environment class that is used by dataflow analyses 104824e7fdSDimitry Andric // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 114824e7fdSDimitry Andric // program at given program points. 124824e7fdSDimitry Andric // 134824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 144824e7fdSDimitry Andric 154824e7fdSDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 164824e7fdSDimitry Andric #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 174824e7fdSDimitry Andric 1804eeddc0SDimitry Andric #include "clang/AST/Decl.h" 1904eeddc0SDimitry Andric #include "clang/AST/DeclBase.h" 2004eeddc0SDimitry Andric #include "clang/AST/Expr.h" 2104eeddc0SDimitry Andric #include "clang/AST/Type.h" 22*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h" 2304eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 240eae32dcSDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2506c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h" 2606c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Logger.h" 2704eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/StorageLocation.h" 2804eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2904eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 3004eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 3106c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h" 3206c3fb27SDimitry Andric #include "llvm/Support/Compiler.h" 33bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h" 34*0fca6ea1SDimitry Andric #include <cassert> 3504eeddc0SDimitry Andric #include <memory> 3604eeddc0SDimitry Andric #include <type_traits> 3704eeddc0SDimitry Andric #include <utility> 38*0fca6ea1SDimitry Andric #include <vector> 390eae32dcSDimitry Andric 404824e7fdSDimitry Andric namespace clang { 414824e7fdSDimitry Andric namespace dataflow { 424824e7fdSDimitry Andric 43bdd1243dSDimitry Andric /// Indicates the result of a tentative comparison. 44bdd1243dSDimitry Andric enum class ComparisonResult { 45bdd1243dSDimitry Andric Same, 46bdd1243dSDimitry Andric Different, 47bdd1243dSDimitry Andric Unknown, 48bdd1243dSDimitry Andric }; 49bdd1243dSDimitry Andric 50*0fca6ea1SDimitry Andric /// The result of a `widen` operation. 51*0fca6ea1SDimitry Andric struct WidenResult { 52*0fca6ea1SDimitry Andric /// Non-null pointer to a potentially widened version of the input value. 53*0fca6ea1SDimitry Andric Value *V; 54*0fca6ea1SDimitry Andric /// Whether `V` represents a "change" (that is, a different value) with 55*0fca6ea1SDimitry Andric /// respect to the previous value in the sequence. 56*0fca6ea1SDimitry Andric LatticeEffect Effect; 57*0fca6ea1SDimitry Andric }; 58*0fca6ea1SDimitry Andric 594824e7fdSDimitry Andric /// Holds the state of the program (store and heap) at a given program point. 6081ad6265SDimitry Andric /// 6181ad6265SDimitry Andric /// WARNING: Symbolic values that are created by the environment for static 6281ad6265SDimitry Andric /// local and global variables are not currently invalidated on function calls. 6381ad6265SDimitry Andric /// This is unsound and should be taken into account when designing dataflow 6481ad6265SDimitry Andric /// analyses. 650eae32dcSDimitry Andric class Environment { 660eae32dcSDimitry Andric public: 671fd87a68SDimitry Andric /// Supplements `Environment` with non-standard comparison and join 681fd87a68SDimitry Andric /// operations. 691fd87a68SDimitry Andric class ValueModel { 7004eeddc0SDimitry Andric public: 711fd87a68SDimitry Andric virtual ~ValueModel() = default; 720eae32dcSDimitry Andric 73bdd1243dSDimitry Andric /// Returns: 74bdd1243dSDimitry Andric /// `Same`: `Val1` is equivalent to `Val2`, according to the model. 75bdd1243dSDimitry Andric /// `Different`: `Val1` is distinct from `Val2`, according to the model. 76bdd1243dSDimitry Andric /// `Unknown`: The model can't determine a relationship between `Val1` and 77bdd1243dSDimitry Andric /// `Val2`. 7804eeddc0SDimitry Andric /// 7904eeddc0SDimitry Andric /// Requirements: 8004eeddc0SDimitry Andric /// 8104eeddc0SDimitry Andric /// `Val1` and `Val2` must be distinct. 821fd87a68SDimitry Andric /// 831fd87a68SDimitry Andric /// `Val1` and `Val2` must model values of type `Type`. 8481ad6265SDimitry Andric /// 8581ad6265SDimitry Andric /// `Val1` and `Val2` must be assigned to the same storage location in 8681ad6265SDimitry Andric /// `Env1` and `Env2` respectively. compare(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2)87bdd1243dSDimitry Andric virtual ComparisonResult compare(QualType Type, const Value &Val1, 8881ad6265SDimitry Andric const Environment &Env1, const Value &Val2, 8981ad6265SDimitry Andric const Environment &Env2) { 90*0fca6ea1SDimitry Andric // FIXME: Consider adding `QualType` to `Value` and removing the `Type` 911fd87a68SDimitry Andric // argument here. 92bdd1243dSDimitry Andric return ComparisonResult::Unknown; 931fd87a68SDimitry Andric } 941fd87a68SDimitry Andric 95*0fca6ea1SDimitry Andric /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should 96*0fca6ea1SDimitry Andric /// obey the properties of a lattice join. 9781ad6265SDimitry Andric /// 9881ad6265SDimitry Andric /// `Env1` and `Env2` can be used to query child values and path condition 9981ad6265SDimitry Andric /// implications of `Val1` and `Val2` respectively. 1001fd87a68SDimitry Andric /// 1011fd87a68SDimitry Andric /// Requirements: 1021fd87a68SDimitry Andric /// 1031fd87a68SDimitry Andric /// `Val1` and `Val2` must be distinct. 1041fd87a68SDimitry Andric /// 105*0fca6ea1SDimitry Andric /// `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`. 10681ad6265SDimitry Andric /// 10781ad6265SDimitry Andric /// `Val1` and `Val2` must be assigned to the same storage location in 10881ad6265SDimitry Andric /// `Env1` and `Env2` respectively. join(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2,Value & JoinedVal,Environment & JoinedEnv)109*0fca6ea1SDimitry Andric virtual void join(QualType Type, const Value &Val1, const Environment &Env1, 110*0fca6ea1SDimitry Andric const Value &Val2, const Environment &Env2, 111*0fca6ea1SDimitry Andric Value &JoinedVal, Environment &JoinedEnv) {} 112bdd1243dSDimitry Andric 113bdd1243dSDimitry Andric /// This function may widen the current value -- replace it with an 114bdd1243dSDimitry Andric /// approximation that can reach a fixed point more quickly than iterated 115bdd1243dSDimitry Andric /// application of the transfer function alone. The previous value is 116bdd1243dSDimitry Andric /// provided to inform the choice of widened value. The function must also 117bdd1243dSDimitry Andric /// serve as a comparison operation, by indicating whether the widened value 118bdd1243dSDimitry Andric /// is equivalent to the previous value. 119bdd1243dSDimitry Andric /// 120*0fca6ea1SDimitry Andric /// Returns one of the folowing: 121*0fca6ea1SDimitry Andric /// * `std::nullopt`, if this value is not of interest to the 122*0fca6ea1SDimitry Andric /// model. 123*0fca6ea1SDimitry Andric /// * A `WidenResult` with: 124*0fca6ea1SDimitry Andric /// * A non-null `Value *` that points either to `Current` or a widened 125*0fca6ea1SDimitry Andric /// version of `Current`. This value must be consistent with 126*0fca6ea1SDimitry Andric /// the flow condition of `CurrentEnv`. We particularly caution 127*0fca6ea1SDimitry Andric /// against using `Prev`, which is rarely consistent. 128*0fca6ea1SDimitry Andric /// * A `LatticeEffect` indicating whether the value should be 129*0fca6ea1SDimitry Andric /// considered a new value (`Changed`) or one *equivalent* (if not 130*0fca6ea1SDimitry Andric /// necessarily equal) to `Prev` (`Unchanged`). 131bdd1243dSDimitry Andric /// 132bdd1243dSDimitry Andric /// `PrevEnv` and `CurrentEnv` can be used to query child values and path 133bdd1243dSDimitry Andric /// condition implications of `Prev` and `Current`, respectively. 134bdd1243dSDimitry Andric /// 135bdd1243dSDimitry Andric /// Requirements: 136bdd1243dSDimitry Andric /// 137bdd1243dSDimitry Andric /// `Prev` and `Current` must model values of type `Type`. 138bdd1243dSDimitry Andric /// 139bdd1243dSDimitry Andric /// `Prev` and `Current` must be assigned to the same storage location in 140bdd1243dSDimitry Andric /// `PrevEnv` and `CurrentEnv`, respectively. widen(QualType Type,Value & Prev,const Environment & PrevEnv,Value & Current,Environment & CurrentEnv)141*0fca6ea1SDimitry Andric virtual std::optional<WidenResult> widen(QualType Type, Value &Prev, 142*0fca6ea1SDimitry Andric const Environment &PrevEnv, 143*0fca6ea1SDimitry Andric Value &Current, 144*0fca6ea1SDimitry Andric Environment &CurrentEnv) { 145bdd1243dSDimitry Andric // The default implementation reduces to just comparison, since comparison 146bdd1243dSDimitry Andric // is required by the API, even if no widening is performed. 147bdd1243dSDimitry Andric switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { 148bdd1243dSDimitry Andric case ComparisonResult::Unknown: 149*0fca6ea1SDimitry Andric return std::nullopt; 150*0fca6ea1SDimitry Andric case ComparisonResult::Same: 151*0fca6ea1SDimitry Andric return WidenResult{&Current, LatticeEffect::Unchanged}; 152*0fca6ea1SDimitry Andric case ComparisonResult::Different: 153*0fca6ea1SDimitry Andric return WidenResult{&Current, LatticeEffect::Changed}; 154bdd1243dSDimitry Andric } 155bdd1243dSDimitry Andric llvm_unreachable("all cases in switch covered"); 156bdd1243dSDimitry Andric } 1570eae32dcSDimitry Andric }; 1584824e7fdSDimitry Andric 15904eeddc0SDimitry Andric /// Creates an environment that uses `DACtx` to store objects that encompass 16004eeddc0SDimitry Andric /// the state of a program. Environment(DataflowAnalysisContext & DACtx)161*0fca6ea1SDimitry Andric explicit Environment(DataflowAnalysisContext &DACtx) 162*0fca6ea1SDimitry Andric : DACtx(&DACtx), 163*0fca6ea1SDimitry Andric FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} 164*0fca6ea1SDimitry Andric 165*0fca6ea1SDimitry Andric /// Creates an environment that uses `DACtx` to store objects that encompass 166*0fca6ea1SDimitry Andric /// the state of a program, with `S` as the statement to analyze. Environment(DataflowAnalysisContext & DACtx,Stmt & S)167*0fca6ea1SDimitry Andric Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) { 168*0fca6ea1SDimitry Andric InitialTargetStmt = &S; 169*0fca6ea1SDimitry Andric } 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric /// Creates an environment that uses `DACtx` to store objects that encompass 172*0fca6ea1SDimitry Andric /// the state of a program, with `FD` as the function to analyze. 173*0fca6ea1SDimitry Andric /// 174*0fca6ea1SDimitry Andric /// Requirements: 175*0fca6ea1SDimitry Andric /// 176*0fca6ea1SDimitry Andric /// The function must have a body, i.e. 177*0fca6ea1SDimitry Andric /// `FunctionDecl::doesThisDecalarationHaveABody()` must be true. Environment(DataflowAnalysisContext & DACtx,const FunctionDecl & FD)178*0fca6ea1SDimitry Andric Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD) 179*0fca6ea1SDimitry Andric : Environment(DACtx, *FD.getBody()) { 180*0fca6ea1SDimitry Andric assert(FD.doesThisDeclarationHaveABody()); 181*0fca6ea1SDimitry Andric InitialTargetFunc = &FD; 182*0fca6ea1SDimitry Andric } 18381ad6265SDimitry Andric 18406c3fb27SDimitry Andric // Copy-constructor is private, Environments should not be copied. See fork(). 18506c3fb27SDimitry Andric Environment &operator=(const Environment &Other) = delete; 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric Environment(Environment &&Other) = default; 18881ad6265SDimitry Andric Environment &operator=(Environment &&Other) = default; 18904eeddc0SDimitry Andric 1905f757f3fSDimitry Andric /// Assigns storage locations and values to all parameters, captures, global 191*0fca6ea1SDimitry Andric /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl` 192*0fca6ea1SDimitry Andric /// passed to the constructor. 1935f757f3fSDimitry Andric /// 194*0fca6ea1SDimitry Andric /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing. 1955f757f3fSDimitry Andric void initialize(); 1965f757f3fSDimitry Andric 19706c3fb27SDimitry Andric /// Returns a new environment that is a copy of this one. 19806c3fb27SDimitry Andric /// 19906c3fb27SDimitry Andric /// The state of the program is initially the same, but can be mutated without 20006c3fb27SDimitry Andric /// affecting the original. 20106c3fb27SDimitry Andric /// 20206c3fb27SDimitry Andric /// However the original should not be further mutated, as this may interfere 20306c3fb27SDimitry Andric /// with the fork. (In practice, values are stored independently, but the 20406c3fb27SDimitry Andric /// forked flow condition references the original). 20506c3fb27SDimitry Andric Environment fork() const; 206bdd1243dSDimitry Andric 207972a253aSDimitry Andric /// Creates and returns an environment to use for an inline analysis of the 208972a253aSDimitry Andric /// callee. Uses the storage location from each argument in the `Call` as the 209972a253aSDimitry Andric /// storage location for the corresponding parameter in the callee. 210972a253aSDimitry Andric /// 211972a253aSDimitry Andric /// Requirements: 212972a253aSDimitry Andric /// 213bdd1243dSDimitry Andric /// The callee of `Call` must be a `FunctionDecl`. 214972a253aSDimitry Andric /// 215972a253aSDimitry Andric /// The body of the callee must not reference globals. 216972a253aSDimitry Andric /// 217972a253aSDimitry Andric /// The arguments of `Call` must map 1:1 to the callee's parameters. 218972a253aSDimitry Andric Environment pushCall(const CallExpr *Call) const; 219bdd1243dSDimitry Andric Environment pushCall(const CXXConstructExpr *Call) const; 220bdd1243dSDimitry Andric 221bdd1243dSDimitry Andric /// Moves gathered information back into `this` from a `CalleeEnv` created via 222bdd1243dSDimitry Andric /// `pushCall`. 22306c3fb27SDimitry Andric void popCall(const CallExpr *Call, const Environment &CalleeEnv); 22406c3fb27SDimitry Andric void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv); 225972a253aSDimitry Andric 2261fd87a68SDimitry Andric /// Returns true if and only if the environment is equivalent to `Other`, i.e 2271fd87a68SDimitry Andric /// the two environments: 2281fd87a68SDimitry Andric /// - have the same mappings from declarations to storage locations, 2291fd87a68SDimitry Andric /// - have the same mappings from expressions to storage locations, 2301fd87a68SDimitry Andric /// - have the same or equivalent (according to `Model`) values assigned to 2311fd87a68SDimitry Andric /// the same storage locations. 2321fd87a68SDimitry Andric /// 2331fd87a68SDimitry Andric /// Requirements: 2341fd87a68SDimitry Andric /// 2351fd87a68SDimitry Andric /// `Other` and `this` must use the same `DataflowAnalysisContext`. 2361fd87a68SDimitry Andric bool equivalentTo(const Environment &Other, 2371fd87a68SDimitry Andric Environment::ValueModel &Model) const; 23804eeddc0SDimitry Andric 239*0fca6ea1SDimitry Andric /// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join. 240*0fca6ea1SDimitry Andric /// If the join happens within a full expression, expression state should be 241*0fca6ea1SDimitry Andric /// kept; otherwise, we can discard it. 242*0fca6ea1SDimitry Andric enum ExprJoinBehavior { 243*0fca6ea1SDimitry Andric DiscardExprState, 244*0fca6ea1SDimitry Andric KeepExprState, 245*0fca6ea1SDimitry Andric }; 246*0fca6ea1SDimitry Andric 24706c3fb27SDimitry Andric /// Joins two environments by taking the intersection of storage locations and 24806c3fb27SDimitry Andric /// values that are stored in them. Distinct values that are assigned to the 24906c3fb27SDimitry Andric /// same storage locations in `EnvA` and `EnvB` are merged using `Model`. 2501fd87a68SDimitry Andric /// 2511fd87a68SDimitry Andric /// Requirements: 2521fd87a68SDimitry Andric /// 25306c3fb27SDimitry Andric /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`. 25406c3fb27SDimitry Andric static Environment join(const Environment &EnvA, const Environment &EnvB, 255*0fca6ea1SDimitry Andric Environment::ValueModel &Model, 256*0fca6ea1SDimitry Andric ExprJoinBehavior ExprBehavior); 257*0fca6ea1SDimitry Andric 258*0fca6ea1SDimitry Andric /// Returns a value that approximates both `Val1` and `Val2`, or null if no 259*0fca6ea1SDimitry Andric /// such value can be produced. 260*0fca6ea1SDimitry Andric /// 261*0fca6ea1SDimitry Andric /// `Env1` and `Env2` can be used to query child values and path condition 262*0fca6ea1SDimitry Andric /// implications of `Val1` and `Val2` respectively. The joined value will be 263*0fca6ea1SDimitry Andric /// produced in `JoinedEnv`. 264*0fca6ea1SDimitry Andric /// 265*0fca6ea1SDimitry Andric /// Requirements: 266*0fca6ea1SDimitry Andric /// 267*0fca6ea1SDimitry Andric /// `Val1` and `Val2` must model values of type `Type`. 268*0fca6ea1SDimitry Andric static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1, 269*0fca6ea1SDimitry Andric Value *Val2, const Environment &Env2, 270*0fca6ea1SDimitry Andric Environment &JoinedEnv, 2711fd87a68SDimitry Andric Environment::ValueModel &Model); 27204eeddc0SDimitry Andric 273bdd1243dSDimitry Andric /// Widens the environment point-wise, using `PrevEnv` as needed to inform the 274bdd1243dSDimitry Andric /// approximation. 275bdd1243dSDimitry Andric /// 276bdd1243dSDimitry Andric /// Requirements: 277bdd1243dSDimitry Andric /// 278bdd1243dSDimitry Andric /// `PrevEnv` must be the immediate previous version of the environment. 279bdd1243dSDimitry Andric /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. 280*0fca6ea1SDimitry Andric LatticeEffect widen(const Environment &PrevEnv, 281bdd1243dSDimitry Andric Environment::ValueModel &Model); 282bdd1243dSDimitry Andric 28304eeddc0SDimitry Andric // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, 28404eeddc0SDimitry Andric // `getStableStorageLocation`, or something more appropriate. 28504eeddc0SDimitry Andric 28604eeddc0SDimitry Andric /// Creates a storage location appropriate for `Type`. Does not assign a value 28704eeddc0SDimitry Andric /// to the returned storage location in the environment. 28804eeddc0SDimitry Andric /// 28904eeddc0SDimitry Andric /// Requirements: 29004eeddc0SDimitry Andric /// 29104eeddc0SDimitry Andric /// `Type` must not be null. 29204eeddc0SDimitry Andric StorageLocation &createStorageLocation(QualType Type); 29304eeddc0SDimitry Andric 29404eeddc0SDimitry Andric /// Creates a storage location for `D`. Does not assign the returned storage 29504eeddc0SDimitry Andric /// location to `D` in the environment. Does not assign a value to the 29604eeddc0SDimitry Andric /// returned storage location in the environment. 2975f757f3fSDimitry Andric StorageLocation &createStorageLocation(const ValueDecl &D); 29804eeddc0SDimitry Andric 29904eeddc0SDimitry Andric /// Creates a storage location for `E`. Does not assign the returned storage 30004eeddc0SDimitry Andric /// location to `E` in the environment. Does not assign a value to the 30104eeddc0SDimitry Andric /// returned storage location in the environment. 30204eeddc0SDimitry Andric StorageLocation &createStorageLocation(const Expr &E); 30304eeddc0SDimitry Andric 30404eeddc0SDimitry Andric /// Assigns `Loc` as the storage location of `D` in the environment. 30504eeddc0SDimitry Andric /// 30604eeddc0SDimitry Andric /// Requirements: 30704eeddc0SDimitry Andric /// 30806c3fb27SDimitry Andric /// `D` must not already have a storage location in the environment. 30904eeddc0SDimitry Andric void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); 31004eeddc0SDimitry Andric 31106c3fb27SDimitry Andric /// Returns the storage location assigned to `D` in the environment, or null 31206c3fb27SDimitry Andric /// if `D` isn't assigned a storage location in the environment. 31306c3fb27SDimitry Andric StorageLocation *getStorageLocation(const ValueDecl &D) const; 31404eeddc0SDimitry Andric 3155f757f3fSDimitry Andric /// Removes the location assigned to `D` in the environment (if any). 3165f757f3fSDimitry Andric void removeDecl(const ValueDecl &D); 31704eeddc0SDimitry Andric 31806c3fb27SDimitry Andric /// Assigns `Loc` as the storage location of the glvalue `E` in the 31906c3fb27SDimitry Andric /// environment. 32006c3fb27SDimitry Andric /// 32106c3fb27SDimitry Andric /// Requirements: 32206c3fb27SDimitry Andric /// 32306c3fb27SDimitry Andric /// `E` must not be assigned a storage location in the environment. 32406c3fb27SDimitry Andric /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 3255f757f3fSDimitry Andric void setStorageLocation(const Expr &E, StorageLocation &Loc); 32604eeddc0SDimitry Andric 32706c3fb27SDimitry Andric /// Returns the storage location assigned to the glvalue `E` in the 32806c3fb27SDimitry Andric /// environment, or null if `E` isn't assigned a storage location in the 32906c3fb27SDimitry Andric /// environment. 33006c3fb27SDimitry Andric /// 33106c3fb27SDimitry Andric /// Requirements: 33206c3fb27SDimitry Andric /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 3335f757f3fSDimitry Andric StorageLocation *getStorageLocation(const Expr &E) const; 33406c3fb27SDimitry Andric 335cb14a3feSDimitry Andric /// Returns the result of casting `getStorageLocation(...)` to a subclass of 336cb14a3feSDimitry Andric /// `StorageLocation` (using `cast_or_null<T>`). 337cb14a3feSDimitry Andric /// This assert-fails if the result of `getStorageLocation(...)` is not of 338cb14a3feSDimitry Andric /// type `T *`; if the storage location is not guaranteed to have type `T *`, 339cb14a3feSDimitry Andric /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead. 340cb14a3feSDimitry Andric template <typename T> 341cb14a3feSDimitry Andric std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> get(const ValueDecl & D)342cb14a3feSDimitry Andric get(const ValueDecl &D) const { 343cb14a3feSDimitry Andric return cast_or_null<T>(getStorageLocation(D)); 344cb14a3feSDimitry Andric } 345cb14a3feSDimitry Andric template <typename T> 346cb14a3feSDimitry Andric std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> get(const Expr & E)347cb14a3feSDimitry Andric get(const Expr &E) const { 348cb14a3feSDimitry Andric return cast_or_null<T>(getStorageLocation(E)); 349cb14a3feSDimitry Andric } 350cb14a3feSDimitry Andric 35104eeddc0SDimitry Andric /// Returns the storage location assigned to the `this` pointee in the 35204eeddc0SDimitry Andric /// environment or null if the `this` pointee has no assigned storage location 35304eeddc0SDimitry Andric /// in the environment. getThisPointeeStorageLocation()3545f757f3fSDimitry Andric RecordStorageLocation *getThisPointeeStorageLocation() const { 3555f757f3fSDimitry Andric return ThisPointeeLoc; 3565f757f3fSDimitry Andric } 3575f757f3fSDimitry Andric 3585f757f3fSDimitry Andric /// Sets the storage location assigned to the `this` pointee in the 3595f757f3fSDimitry Andric /// environment. setThisPointeeStorageLocation(RecordStorageLocation & Loc)3605f757f3fSDimitry Andric void setThisPointeeStorageLocation(RecordStorageLocation &Loc) { 3615f757f3fSDimitry Andric ThisPointeeLoc = &Loc; 3625f757f3fSDimitry Andric } 36304eeddc0SDimitry Andric 36406c3fb27SDimitry Andric /// Returns the location of the result object for a record-type prvalue. 36506c3fb27SDimitry Andric /// 36606c3fb27SDimitry Andric /// In C++, prvalues of record type serve only a limited purpose: They can 36706c3fb27SDimitry Andric /// only be used to initialize a result object (e.g. a variable or a 36806c3fb27SDimitry Andric /// temporary). This function returns the location of that result object. 36906c3fb27SDimitry Andric /// 37006c3fb27SDimitry Andric /// When creating a prvalue of record type, we already need the storage 37106c3fb27SDimitry Andric /// location of the result object to pass in `this`, even though prvalues are 37206c3fb27SDimitry Andric /// otherwise not associated with storage locations. 37306c3fb27SDimitry Andric /// 37406c3fb27SDimitry Andric /// Requirements: 37506c3fb27SDimitry Andric /// `E` must be a prvalue of record type. 376cb14a3feSDimitry Andric RecordStorageLocation & 377cb14a3feSDimitry Andric getResultObjectLocation(const Expr &RecordPRValue) const; 37806c3fb27SDimitry Andric 379*0fca6ea1SDimitry Andric /// Returns the return value of the function currently being analyzed. 380*0fca6ea1SDimitry Andric /// This can be null if: 38106c3fb27SDimitry Andric /// - The function has a void return type 38206c3fb27SDimitry Andric /// - No return value could be determined for the function, for example 38306c3fb27SDimitry Andric /// because it calls a function without a body. 38406c3fb27SDimitry Andric /// 38506c3fb27SDimitry Andric /// Requirements: 386*0fca6ea1SDimitry Andric /// The current analysis target must be a function and must have a 387*0fca6ea1SDimitry Andric /// non-reference return type. getReturnValue()38806c3fb27SDimitry Andric Value *getReturnValue() const { 38906c3fb27SDimitry Andric assert(getCurrentFunc() != nullptr && 39006c3fb27SDimitry Andric !getCurrentFunc()->getReturnType()->isReferenceType()); 39106c3fb27SDimitry Andric return ReturnVal; 39206c3fb27SDimitry Andric } 39306c3fb27SDimitry Andric 394*0fca6ea1SDimitry Andric /// Returns the storage location for the reference returned by the function 395*0fca6ea1SDimitry Andric /// currently being analyzed. This can be null if the function doesn't return 396*0fca6ea1SDimitry Andric /// a single consistent reference. 39706c3fb27SDimitry Andric /// 39806c3fb27SDimitry Andric /// Requirements: 399*0fca6ea1SDimitry Andric /// The current analysis target must be a function and must have a reference 400*0fca6ea1SDimitry Andric /// return type. getReturnStorageLocation()40106c3fb27SDimitry Andric StorageLocation *getReturnStorageLocation() const { 40206c3fb27SDimitry Andric assert(getCurrentFunc() != nullptr && 40306c3fb27SDimitry Andric getCurrentFunc()->getReturnType()->isReferenceType()); 40406c3fb27SDimitry Andric return ReturnLoc; 40506c3fb27SDimitry Andric } 40606c3fb27SDimitry Andric 407*0fca6ea1SDimitry Andric /// Sets the return value of the function currently being analyzed. 40806c3fb27SDimitry Andric /// 40906c3fb27SDimitry Andric /// Requirements: 410*0fca6ea1SDimitry Andric /// The current analysis target must be a function and must have a 411*0fca6ea1SDimitry Andric /// non-reference return type. setReturnValue(Value * Val)41206c3fb27SDimitry Andric void setReturnValue(Value *Val) { 41306c3fb27SDimitry Andric assert(getCurrentFunc() != nullptr && 41406c3fb27SDimitry Andric !getCurrentFunc()->getReturnType()->isReferenceType()); 41506c3fb27SDimitry Andric ReturnVal = Val; 41606c3fb27SDimitry Andric } 41706c3fb27SDimitry Andric 418*0fca6ea1SDimitry Andric /// Sets the storage location for the reference returned by the function 419*0fca6ea1SDimitry Andric /// currently being analyzed. 42006c3fb27SDimitry Andric /// 42106c3fb27SDimitry Andric /// Requirements: 422*0fca6ea1SDimitry Andric /// The current analysis target must be a function and must have a reference 423*0fca6ea1SDimitry Andric /// return type. setReturnStorageLocation(StorageLocation * Loc)42406c3fb27SDimitry Andric void setReturnStorageLocation(StorageLocation *Loc) { 42506c3fb27SDimitry Andric assert(getCurrentFunc() != nullptr && 42606c3fb27SDimitry Andric getCurrentFunc()->getReturnType()->isReferenceType()); 42706c3fb27SDimitry Andric ReturnLoc = Loc; 42806c3fb27SDimitry Andric } 429bdd1243dSDimitry Andric 43081ad6265SDimitry Andric /// Returns a pointer value that represents a null pointer. Calls with 43181ad6265SDimitry Andric /// `PointeeType` that are canonically equivalent will return the same result. 43281ad6265SDimitry Andric PointerValue &getOrCreateNullPointerValue(QualType PointeeType); 43381ad6265SDimitry Andric 43404eeddc0SDimitry Andric /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 43506c3fb27SDimitry Andric /// returns null. 43606c3fb27SDimitry Andric /// 43706c3fb27SDimitry Andric /// If `Type` is a pointer or reference type, creates all the necessary 43806c3fb27SDimitry Andric /// storage locations and values for indirections until it finds a 43904eeddc0SDimitry Andric /// non-pointer/non-reference type. 44004eeddc0SDimitry Andric /// 44106c3fb27SDimitry Andric /// If `Type` is one of the following types, this function will always return 44206c3fb27SDimitry Andric /// a non-null pointer: 44306c3fb27SDimitry Andric /// - `bool` 44406c3fb27SDimitry Andric /// - Any integer type 44506c3fb27SDimitry Andric /// 44604eeddc0SDimitry Andric /// Requirements: 44704eeddc0SDimitry Andric /// 448*0fca6ea1SDimitry Andric /// - `Type` must not be null. 449*0fca6ea1SDimitry Andric /// - `Type` must not be a reference type or record type. 45004eeddc0SDimitry Andric Value *createValue(QualType Type); 45104eeddc0SDimitry Andric 45206c3fb27SDimitry Andric /// Creates an object (i.e. a storage location with an associated value) of 45306c3fb27SDimitry Andric /// type `Ty`. If `InitExpr` is non-null and has a value associated with it, 45406c3fb27SDimitry Andric /// initializes the object with this value. Otherwise, initializes the object 45506c3fb27SDimitry Andric /// with a value created using `createValue()`. 45606c3fb27SDimitry Andric StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) { 45706c3fb27SDimitry Andric return createObjectInternal(nullptr, Ty, InitExpr); 45806c3fb27SDimitry Andric } 45906c3fb27SDimitry Andric 46006c3fb27SDimitry Andric /// Creates an object for the variable declaration `D`. If `D` has an 46106c3fb27SDimitry Andric /// initializer and this initializer is associated with a value, initializes 46206c3fb27SDimitry Andric /// the object with this value. Otherwise, initializes the object with a 46306c3fb27SDimitry Andric /// value created using `createValue()`. Uses the storage location returned by 46406c3fb27SDimitry Andric /// `DataflowAnalysisContext::getStableStorageLocation(D)`. createObject(const VarDecl & D)46506c3fb27SDimitry Andric StorageLocation &createObject(const VarDecl &D) { 46606c3fb27SDimitry Andric return createObjectInternal(&D, D.getType(), D.getInit()); 46706c3fb27SDimitry Andric } 46806c3fb27SDimitry Andric 46906c3fb27SDimitry Andric /// Creates an object for the variable declaration `D`. If `InitExpr` is 47006c3fb27SDimitry Andric /// non-null and has a value associated with it, initializes the object with 47106c3fb27SDimitry Andric /// this value. Otherwise, initializes the object with a value created using 47206c3fb27SDimitry Andric /// `createValue()`. Uses the storage location returned by 47306c3fb27SDimitry Andric /// `DataflowAnalysisContext::getStableStorageLocation(D)`. createObject(const ValueDecl & D,const Expr * InitExpr)4745f757f3fSDimitry Andric StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) { 47506c3fb27SDimitry Andric return createObjectInternal(&D, D.getType(), InitExpr); 47606c3fb27SDimitry Andric } 47706c3fb27SDimitry Andric 478*0fca6ea1SDimitry Andric /// Initializes the fields (including synthetic fields) of `Loc` with values, 479*0fca6ea1SDimitry Andric /// unless values of the field type are not supported or we hit one of the 480*0fca6ea1SDimitry Andric /// limits at which we stop producing values. 481*0fca6ea1SDimitry Andric /// If a field already has a value, that value is preserved. 482*0fca6ea1SDimitry Andric /// If `Type` is provided, initializes only those fields that are modeled for 483*0fca6ea1SDimitry Andric /// `Type`; this is intended for use in cases where `Loc` is a derived type 484*0fca6ea1SDimitry Andric /// and we only want to initialize the fields of a base type. 485*0fca6ea1SDimitry Andric void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type); initializeFieldsWithValues(RecordStorageLocation & Loc)486*0fca6ea1SDimitry Andric void initializeFieldsWithValues(RecordStorageLocation &Loc) { 487*0fca6ea1SDimitry Andric initializeFieldsWithValues(Loc, Loc.getType()); 488*0fca6ea1SDimitry Andric } 489*0fca6ea1SDimitry Andric 49004eeddc0SDimitry Andric /// Assigns `Val` as the value of `Loc` in the environment. 491*0fca6ea1SDimitry Andric /// 492*0fca6ea1SDimitry Andric /// Requirements: 493*0fca6ea1SDimitry Andric /// 494*0fca6ea1SDimitry Andric /// `Loc` must not be a `RecordStorageLocation`. 49504eeddc0SDimitry Andric void setValue(const StorageLocation &Loc, Value &Val); 49604eeddc0SDimitry Andric 49706c3fb27SDimitry Andric /// Clears any association between `Loc` and a value in the environment. clearValue(const StorageLocation & Loc)49806c3fb27SDimitry Andric void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); } 49906c3fb27SDimitry Andric 50006c3fb27SDimitry Andric /// Assigns `Val` as the value of the prvalue `E` in the environment. 50106c3fb27SDimitry Andric /// 50206c3fb27SDimitry Andric /// Requirements: 50306c3fb27SDimitry Andric /// 504*0fca6ea1SDimitry Andric /// - `E` must be a prvalue. 505*0fca6ea1SDimitry Andric /// - `E` must not have record type. 5065f757f3fSDimitry Andric void setValue(const Expr &E, Value &Val); 50706c3fb27SDimitry Andric 50804eeddc0SDimitry Andric /// Returns the value assigned to `Loc` in the environment or null if `Loc` 50904eeddc0SDimitry Andric /// isn't assigned a value in the environment. 510*0fca6ea1SDimitry Andric /// 511*0fca6ea1SDimitry Andric /// Requirements: 512*0fca6ea1SDimitry Andric /// 513*0fca6ea1SDimitry Andric /// `Loc` must not be a `RecordStorageLocation`. 51404eeddc0SDimitry Andric Value *getValue(const StorageLocation &Loc) const; 51504eeddc0SDimitry Andric 5165f757f3fSDimitry Andric /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a 5175f757f3fSDimitry Andric /// storage location in the environment, otherwise returns null. 518*0fca6ea1SDimitry Andric /// 519*0fca6ea1SDimitry Andric /// Requirements: 520*0fca6ea1SDimitry Andric /// 521*0fca6ea1SDimitry Andric /// `D` must not have record type. 52206c3fb27SDimitry Andric Value *getValue(const ValueDecl &D) const; 52304eeddc0SDimitry Andric 5245f757f3fSDimitry Andric /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a 5255f757f3fSDimitry Andric /// storage location in the environment, otherwise returns null. 5265f757f3fSDimitry Andric Value *getValue(const Expr &E) const; 52706c3fb27SDimitry Andric 528cb14a3feSDimitry Andric /// Returns the result of casting `getValue(...)` to a subclass of `Value` 529cb14a3feSDimitry Andric /// (using `cast_or_null<T>`). 530cb14a3feSDimitry Andric /// This assert-fails if the result of `getValue(...)` is not of type `T *`; 531cb14a3feSDimitry Andric /// if the value is not guaranteed to have type `T *`, consider using 532cb14a3feSDimitry Andric /// `dyn_cast_or_null<T>(getValue(...))` instead. 533cb14a3feSDimitry Andric template <typename T> 534cb14a3feSDimitry Andric std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const StorageLocation & Loc)535cb14a3feSDimitry Andric get(const StorageLocation &Loc) const { 536cb14a3feSDimitry Andric return cast_or_null<T>(getValue(Loc)); 537cb14a3feSDimitry Andric } 538cb14a3feSDimitry Andric template <typename T> 539cb14a3feSDimitry Andric std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const ValueDecl & D)540cb14a3feSDimitry Andric get(const ValueDecl &D) const { 541cb14a3feSDimitry Andric return cast_or_null<T>(getValue(D)); 542cb14a3feSDimitry Andric } 543cb14a3feSDimitry Andric template <typename T> get(const Expr & E)544cb14a3feSDimitry Andric std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const { 545cb14a3feSDimitry Andric return cast_or_null<T>(getValue(E)); 546cb14a3feSDimitry Andric } 547cb14a3feSDimitry Andric 54806c3fb27SDimitry Andric // FIXME: should we deprecate the following & call arena().create() directly? 54906c3fb27SDimitry Andric 55006c3fb27SDimitry Andric /// Creates a `T` (some subclass of `Value`), forwarding `args` to the 55106c3fb27SDimitry Andric /// constructor, and returns a reference to it. 55206c3fb27SDimitry Andric /// 55306c3fb27SDimitry Andric /// The analysis context takes ownership of the created object. The object 55406c3fb27SDimitry Andric /// will be destroyed when the analysis context is destroyed. 55506c3fb27SDimitry Andric template <typename T, typename... Args> 55606c3fb27SDimitry Andric std::enable_if_t<std::is_base_of<Value, T>::value, T &> create(Args &&...args)55706c3fb27SDimitry Andric create(Args &&...args) { 55806c3fb27SDimitry Andric return arena().create<T>(std::forward<Args>(args)...); 55904eeddc0SDimitry Andric } 56004eeddc0SDimitry Andric 56106c3fb27SDimitry Andric /// Returns a symbolic integer value that models an integer literal equal to 56206c3fb27SDimitry Andric /// `Value` getIntLiteralValue(llvm::APInt Value)56306c3fb27SDimitry Andric IntegerValue &getIntLiteralValue(llvm::APInt Value) const { 56406c3fb27SDimitry Andric return arena().makeIntLiteral(Value); 56504eeddc0SDimitry Andric } 56604eeddc0SDimitry Andric 56704eeddc0SDimitry Andric /// Returns a symbolic boolean value that models a boolean literal equal to 56804eeddc0SDimitry Andric /// `Value` getBoolLiteralValue(bool Value)5695f757f3fSDimitry Andric BoolValue &getBoolLiteralValue(bool Value) const { 5705f757f3fSDimitry Andric return arena().makeBoolValue(arena().makeLiteral(Value)); 57104eeddc0SDimitry Andric } 57204eeddc0SDimitry Andric 57381ad6265SDimitry Andric /// Returns an atomic boolean value. makeAtomicBoolValue()57481ad6265SDimitry Andric BoolValue &makeAtomicBoolValue() const { 57506c3fb27SDimitry Andric return arena().makeAtomValue(); 57681ad6265SDimitry Andric } 57781ad6265SDimitry Andric 578bdd1243dSDimitry Andric /// Returns a unique instance of boolean Top. makeTopBoolValue()579bdd1243dSDimitry Andric BoolValue &makeTopBoolValue() const { 58006c3fb27SDimitry Andric return arena().makeTopValue(); 581bdd1243dSDimitry Andric } 582bdd1243dSDimitry Andric 58381ad6265SDimitry Andric /// Returns a boolean value that represents the conjunction of `LHS` and 58481ad6265SDimitry Andric /// `RHS`. Subsequent calls with the same arguments, regardless of their 58581ad6265SDimitry Andric /// order, will return the same result. If the given boolean values represent 58681ad6265SDimitry Andric /// the same value, the result will be the value itself. makeAnd(BoolValue & LHS,BoolValue & RHS)58781ad6265SDimitry Andric BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const { 58806c3fb27SDimitry Andric return arena().makeBoolValue( 58906c3fb27SDimitry Andric arena().makeAnd(LHS.formula(), RHS.formula())); 59081ad6265SDimitry Andric } 59181ad6265SDimitry Andric 59281ad6265SDimitry Andric /// Returns a boolean value that represents the disjunction of `LHS` and 59381ad6265SDimitry Andric /// `RHS`. Subsequent calls with the same arguments, regardless of their 59481ad6265SDimitry Andric /// order, will return the same result. If the given boolean values represent 59581ad6265SDimitry Andric /// the same value, the result will be the value itself. makeOr(BoolValue & LHS,BoolValue & RHS)59681ad6265SDimitry Andric BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const { 59706c3fb27SDimitry Andric return arena().makeBoolValue( 59806c3fb27SDimitry Andric arena().makeOr(LHS.formula(), RHS.formula())); 59981ad6265SDimitry Andric } 60081ad6265SDimitry Andric 60181ad6265SDimitry Andric /// Returns a boolean value that represents the negation of `Val`. Subsequent 60281ad6265SDimitry Andric /// calls with the same argument will return the same result. makeNot(BoolValue & Val)60381ad6265SDimitry Andric BoolValue &makeNot(BoolValue &Val) const { 60406c3fb27SDimitry Andric return arena().makeBoolValue(arena().makeNot(Val.formula())); 60581ad6265SDimitry Andric } 60681ad6265SDimitry Andric 60781ad6265SDimitry Andric /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with 60881ad6265SDimitry Andric /// the same arguments, will return the same result. If the given boolean 60981ad6265SDimitry Andric /// values represent the same value, the result will be a value that 61081ad6265SDimitry Andric /// represents the true boolean literal. makeImplication(BoolValue & LHS,BoolValue & RHS)61181ad6265SDimitry Andric BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const { 61206c3fb27SDimitry Andric return arena().makeBoolValue( 61306c3fb27SDimitry Andric arena().makeImplies(LHS.formula(), RHS.formula())); 61481ad6265SDimitry Andric } 61581ad6265SDimitry Andric 61681ad6265SDimitry Andric /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with 61781ad6265SDimitry Andric /// the same arguments, regardless of their order, will return the same 61881ad6265SDimitry Andric /// result. If the given boolean values represent the same value, the result 61981ad6265SDimitry Andric /// will be a value that represents the true boolean literal. makeIff(BoolValue & LHS,BoolValue & RHS)62081ad6265SDimitry Andric BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const { 62106c3fb27SDimitry Andric return arena().makeBoolValue( 62206c3fb27SDimitry Andric arena().makeEquals(LHS.formula(), RHS.formula())); 62381ad6265SDimitry Andric } 62481ad6265SDimitry Andric 62506c3fb27SDimitry Andric /// Returns a boolean variable that identifies the flow condition (FC). 62606c3fb27SDimitry Andric /// 62706c3fb27SDimitry Andric /// The flow condition is a set of facts that are necessarily true when the 62806c3fb27SDimitry Andric /// program reaches the current point, expressed as boolean formulas. 62906c3fb27SDimitry Andric /// The flow condition token is equivalent to the AND of these facts. 63006c3fb27SDimitry Andric /// 63106c3fb27SDimitry Andric /// These may e.g. constrain the value of certain variables. A pointer 63206c3fb27SDimitry Andric /// variable may have a consistent modeled PointerValue throughout, but at a 63306c3fb27SDimitry Andric /// given point the Environment may tell us that the value must be non-null. 63406c3fb27SDimitry Andric /// 63506c3fb27SDimitry Andric /// The FC is necessary but not sufficient for this point to be reachable. 63606c3fb27SDimitry Andric /// In particular, where the FC token appears in flow conditions of successor 63706c3fb27SDimitry Andric /// environments, it means "point X may have been reached", not 63806c3fb27SDimitry Andric /// "point X was reached". getFlowConditionToken()63906c3fb27SDimitry Andric Atom getFlowConditionToken() const { return FlowConditionToken; } 64081ad6265SDimitry Andric 64106c3fb27SDimitry Andric /// Record a fact that must be true if this point in the program is reached. 6425f757f3fSDimitry Andric void assume(const Formula &); 64381ad6265SDimitry Andric 64406c3fb27SDimitry Andric /// Returns true if the formula is always true when this point is reached. 6455f757f3fSDimitry Andric /// Returns false if the formula may be false (or the flow condition isn't 6465f757f3fSDimitry Andric /// sufficiently precise to prove that it is true) or if the solver times out. 6475f757f3fSDimitry Andric /// 6485f757f3fSDimitry Andric /// Note that there is an asymmetry between this function and `allows()` in 6495f757f3fSDimitry Andric /// that they both return false if the solver times out. The assumption is 6505f757f3fSDimitry Andric /// that if `proves()` or `allows()` returns true, this will result in a 6515f757f3fSDimitry Andric /// diagnostic, and we want to bias towards false negatives in the case where 6525f757f3fSDimitry Andric /// the solver times out. 6535f757f3fSDimitry Andric bool proves(const Formula &) const; 6545f757f3fSDimitry Andric 6555f757f3fSDimitry Andric /// Returns true if the formula may be true when this point is reached. 6565f757f3fSDimitry Andric /// Returns false if the formula is always false when this point is reached 6575f757f3fSDimitry Andric /// (or the flow condition is overly constraining) or if the solver times out. 6585f757f3fSDimitry Andric bool allows(const Formula &) const; 65981ad6265SDimitry Andric 66006c3fb27SDimitry Andric /// Returns the function currently being analyzed, or null if the code being 66106c3fb27SDimitry Andric /// analyzed isn't part of a function. getCurrentFunc()66206c3fb27SDimitry Andric const FunctionDecl *getCurrentFunc() const { 663*0fca6ea1SDimitry Andric return CallStack.empty() ? InitialTargetFunc : CallStack.back(); 66406c3fb27SDimitry Andric } 66506c3fb27SDimitry Andric 666*0fca6ea1SDimitry Andric /// Returns the size of the call stack, not counting the initial analysis 667*0fca6ea1SDimitry Andric /// target. callStackSize()6685f757f3fSDimitry Andric size_t callStackSize() const { return CallStack.size(); } 6695f757f3fSDimitry Andric 670bdd1243dSDimitry Andric /// Returns whether this `Environment` can be extended to analyze the given 671*0fca6ea1SDimitry Andric /// `Callee` (i.e. if `pushCall` can be used). 672*0fca6ea1SDimitry Andric /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack 673*0fca6ea1SDimitry Andric /// (i.e. the maximum value that `callStackSize()` may assume after the call). 674*0fca6ea1SDimitry Andric bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const; 675bdd1243dSDimitry Andric 67606c3fb27SDimitry Andric /// Returns the `DataflowAnalysisContext` used by the environment. getDataflowAnalysisContext()67706c3fb27SDimitry Andric DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; } 67806c3fb27SDimitry Andric arena()67906c3fb27SDimitry Andric Arena &arena() const { return DACtx->arena(); } 680bdd1243dSDimitry Andric 681fcaf7f86SDimitry Andric LLVM_DUMP_METHOD void dump() const; 682bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; 683fcaf7f86SDimitry Andric 68404eeddc0SDimitry Andric private: 685*0fca6ea1SDimitry Andric using PrValueToResultObject = 686*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, RecordStorageLocation *>; 687*0fca6ea1SDimitry Andric 68806c3fb27SDimitry Andric // The copy-constructor is for use in fork() only. 68906c3fb27SDimitry Andric Environment(const Environment &) = default; 69006c3fb27SDimitry Andric 69104eeddc0SDimitry Andric /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 69204eeddc0SDimitry Andric /// return null. 69304eeddc0SDimitry Andric /// 69404eeddc0SDimitry Andric /// Recursively initializes storage locations and values until it sees a 69504eeddc0SDimitry Andric /// self-referential pointer or reference type. `Visited` is used to track 69604eeddc0SDimitry Andric /// which types appeared in the reference/pointer chain in order to avoid 69704eeddc0SDimitry Andric /// creating a cyclic dependency with self-referential pointers/references. 69804eeddc0SDimitry Andric /// 69904eeddc0SDimitry Andric /// Requirements: 70004eeddc0SDimitry Andric /// 70104eeddc0SDimitry Andric /// `Type` must not be null. 70204eeddc0SDimitry Andric Value *createValueUnlessSelfReferential(QualType Type, 70381ad6265SDimitry Andric llvm::DenseSet<QualType> &Visited, 70481ad6265SDimitry Andric int Depth, int &CreatedValuesCount); 70504eeddc0SDimitry Andric 70606c3fb27SDimitry Andric /// Creates a storage location for `Ty`. Also creates and associates a value 70706c3fb27SDimitry Andric /// with the storage location, unless values of this type are not supported or 70806c3fb27SDimitry Andric /// we hit one of the limits at which we stop producing values (controlled by 70906c3fb27SDimitry Andric /// `Visited`, `Depth`, and `CreatedValuesCount`). 71006c3fb27SDimitry Andric StorageLocation &createLocAndMaybeValue(QualType Ty, 71106c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited, 71206c3fb27SDimitry Andric int Depth, int &CreatedValuesCount); 71306c3fb27SDimitry Andric 714*0fca6ea1SDimitry Andric /// Initializes the fields (including synthetic fields) of `Loc` with values, 715*0fca6ea1SDimitry Andric /// unless values of the field type are not supported or we hit one of the 716*0fca6ea1SDimitry Andric /// limits at which we stop producing values (controlled by `Visited`, 717*0fca6ea1SDimitry Andric /// `Depth`, and `CreatedValuesCount`). If `Type` is different from 718*0fca6ea1SDimitry Andric /// `Loc.getType()`, initializes only those fields that are modeled for 719*0fca6ea1SDimitry Andric /// `Type`. 720*0fca6ea1SDimitry Andric void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type, 721*0fca6ea1SDimitry Andric llvm::DenseSet<QualType> &Visited, int Depth, 722*0fca6ea1SDimitry Andric int &CreatedValuesCount); 723*0fca6ea1SDimitry Andric 72406c3fb27SDimitry Andric /// Shared implementation of `createObject()` overloads. 72506c3fb27SDimitry Andric /// `D` and `InitExpr` may be null. 7265f757f3fSDimitry Andric StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty, 72706c3fb27SDimitry Andric const Expr *InitExpr); 72806c3fb27SDimitry Andric 729bdd1243dSDimitry Andric /// Shared implementation of `pushCall` overloads. Note that unlike 730bdd1243dSDimitry Andric /// `pushCall`, this member is invoked on the environment of the callee, not 731bdd1243dSDimitry Andric /// of the caller. 732bdd1243dSDimitry Andric void pushCallInternal(const FunctionDecl *FuncDecl, 733bdd1243dSDimitry Andric ArrayRef<const Expr *> Args); 734bdd1243dSDimitry Andric 73506c3fb27SDimitry Andric /// Assigns storage locations and values to all global variables, fields 736*0fca6ea1SDimitry Andric /// and functions in `Referenced`. 737*0fca6ea1SDimitry Andric void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced); 738*0fca6ea1SDimitry Andric 739*0fca6ea1SDimitry Andric static PrValueToResultObject 740*0fca6ea1SDimitry Andric buildResultObjectMap(DataflowAnalysisContext *DACtx, 741*0fca6ea1SDimitry Andric const FunctionDecl *FuncDecl, 742*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc, 743*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal); 744*0fca6ea1SDimitry Andric 745*0fca6ea1SDimitry Andric static PrValueToResultObject 746*0fca6ea1SDimitry Andric buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S, 747*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc, 748*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal); 749bdd1243dSDimitry Andric 75004eeddc0SDimitry Andric // `DACtx` is not null and not owned by this object. 75104eeddc0SDimitry Andric DataflowAnalysisContext *DACtx; 75204eeddc0SDimitry Andric 753*0fca6ea1SDimitry Andric // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`, 754*0fca6ea1SDimitry Andric // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object, 755*0fca6ea1SDimitry Andric // shared between environments in the same call. 756bdd1243dSDimitry Andric // https://github.com/llvm/llvm-project/issues/59005 757bdd1243dSDimitry Andric 758*0fca6ea1SDimitry Andric // The stack of functions called from the initial analysis target. 759*0fca6ea1SDimitry Andric std::vector<const FunctionDecl *> CallStack; 760bdd1243dSDimitry Andric 761*0fca6ea1SDimitry Andric // Initial function to analyze, if a function was passed to the constructor. 762*0fca6ea1SDimitry Andric // Null otherwise. 763*0fca6ea1SDimitry Andric const FunctionDecl *InitialTargetFunc = nullptr; 764*0fca6ea1SDimitry Andric // Top-level statement of the initial analysis target. 765*0fca6ea1SDimitry Andric // If a function was passed to the constructor, this is its body. 766*0fca6ea1SDimitry Andric // If a statement was passed to the constructor, this is that statement. 767*0fca6ea1SDimitry Andric // Null if no analysis target was passed to the constructor. 768*0fca6ea1SDimitry Andric Stmt *InitialTargetStmt = nullptr; 769*0fca6ea1SDimitry Andric 770*0fca6ea1SDimitry Andric // Maps from prvalues of record type to their result objects. Shared between 771*0fca6ea1SDimitry Andric // all environments for the same analysis target. 772*0fca6ea1SDimitry Andric // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr` 773*0fca6ea1SDimitry Andric // here, though the cost is acceptable: The overhead of a `shared_ptr` is 774*0fca6ea1SDimitry Andric // incurred when it is copied, and this happens only relatively rarely (when 775*0fca6ea1SDimitry Andric // we fork the environment). The need for a `shared_ptr` will go away once we 776*0fca6ea1SDimitry Andric // introduce a shared call-context object (see above). 777*0fca6ea1SDimitry Andric std::shared_ptr<PrValueToResultObject> ResultObjectMap; 778*0fca6ea1SDimitry Andric 779*0fca6ea1SDimitry Andric // The following three member variables handle various different types of 780*0fca6ea1SDimitry Andric // return values when the current analysis target is a function. 781*0fca6ea1SDimitry Andric // - If the return type is not a reference and not a record: Value returned 782*0fca6ea1SDimitry Andric // by the function. 78306c3fb27SDimitry Andric Value *ReturnVal = nullptr; 784*0fca6ea1SDimitry Andric // - If the return type is a reference: Storage location of the reference 785*0fca6ea1SDimitry Andric // returned by the function. 786bdd1243dSDimitry Andric StorageLocation *ReturnLoc = nullptr; 787*0fca6ea1SDimitry Andric // - If the return type is a record or the function being analyzed is a 788*0fca6ea1SDimitry Andric // constructor: Storage location into which the return value should be 789*0fca6ea1SDimitry Andric // constructed. 790*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal = nullptr; 791*0fca6ea1SDimitry Andric 792bdd1243dSDimitry Andric // The storage location of the `this` pointee. Should only be null if the 793*0fca6ea1SDimitry Andric // analysis target is not a method. 7945f757f3fSDimitry Andric RecordStorageLocation *ThisPointeeLoc = nullptr; 795bdd1243dSDimitry Andric 7965f757f3fSDimitry Andric // Maps from declarations and glvalue expression to storage locations that are 79704eeddc0SDimitry Andric // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these 79804eeddc0SDimitry Andric // include only storage locations that are in scope for a particular basic 79904eeddc0SDimitry Andric // block. 80004eeddc0SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; 80104eeddc0SDimitry Andric llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; 8025f757f3fSDimitry Andric // Maps from prvalue expressions and storage locations to the values that 8035f757f3fSDimitry Andric // are assigned to them. 80406c3fb27SDimitry Andric // We preserve insertion order so that join/widen process values in 80506c3fb27SDimitry Andric // deterministic sequence. This in turn produces deterministic SAT formulas. 8065f757f3fSDimitry Andric llvm::MapVector<const Expr *, Value *> ExprToVal; 80706c3fb27SDimitry Andric llvm::MapVector<const StorageLocation *, Value *> LocToVal; 80804eeddc0SDimitry Andric 80906c3fb27SDimitry Andric Atom FlowConditionToken; 81004eeddc0SDimitry Andric }; 81104eeddc0SDimitry Andric 81206c3fb27SDimitry Andric /// Returns the storage location for the implicit object of a 81306c3fb27SDimitry Andric /// `CXXMemberCallExpr`, or null if none is defined in the environment. 81406c3fb27SDimitry Andric /// Dereferences the pointer if the member call expression was written using 81506c3fb27SDimitry Andric /// `->`. 8165f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 8175f757f3fSDimitry Andric const Environment &Env); 81806c3fb27SDimitry Andric 81906c3fb27SDimitry Andric /// Returns the storage location for the base object of a `MemberExpr`, or null 82006c3fb27SDimitry Andric /// if none is defined in the environment. Dereferences the pointer if the 82106c3fb27SDimitry Andric /// member expression was written using `->`. 8225f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 82306c3fb27SDimitry Andric const Environment &Env); 82406c3fb27SDimitry Andric 8254824e7fdSDimitry Andric } // namespace dataflow 8264824e7fdSDimitry Andric } // namespace clang 8274824e7fdSDimitry Andric 8284824e7fdSDimitry Andric #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 829