1af7bc39bSStanislav Gatev //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// 2af7bc39bSStanislav Gatev // 3af7bc39bSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4af7bc39bSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information. 5af7bc39bSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6af7bc39bSStanislav Gatev // 7af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===// 8af7bc39bSStanislav Gatev // 9af7bc39bSStanislav Gatev // This file defines an Environment class that is used by dataflow analyses 10af7bc39bSStanislav Gatev // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 11af7bc39bSStanislav Gatev // program at given program points. 12af7bc39bSStanislav Gatev // 13af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===// 14af7bc39bSStanislav Gatev 15af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 16af7bc39bSStanislav Gatev #include "clang/AST/Decl.h" 1799f7d55eSStanislav Gatev #include "clang/AST/DeclCXX.h" 183fed312dSSamira Bazuzi #include "clang/AST/ExprCXX.h" 1971f1932bSmartinboehme #include "clang/AST/RecursiveASTVisitor.h" 2080d9ae9cSSamira Bazuzi #include "clang/AST/Stmt.h" 21af7bc39bSStanislav Gatev #include "clang/AST/Type.h" 229ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/ASTOps.h" 2380d9ae9cSSamira Bazuzi #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 24af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 25af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/Value.h" 26af7bc39bSStanislav Gatev #include "llvm/ADT/DenseMap.h" 27af7bc39bSStanislav Gatev #include "llvm/ADT/DenseSet.h" 287d935d08SSam McCall #include "llvm/ADT/MapVector.h" 2980d9ae9cSSamira Bazuzi #include "llvm/ADT/PointerUnion.h" 30941959d6SDmitri Gribenko #include "llvm/ADT/STLExtras.h" 31e8fce958Smartinboehme #include "llvm/ADT/ScopeExit.h" 32e7481f6eSStanislav Gatev #include "llvm/Support/ErrorHandling.h" 3380d9ae9cSSamira Bazuzi #include <algorithm> 3403dff121SStanislav Gatev #include <cassert> 3580d9ae9cSSamira Bazuzi #include <memory> 36af7bc39bSStanislav Gatev #include <utility> 37af7bc39bSStanislav Gatev 3871f1932bSmartinboehme #define DEBUG_TYPE "dataflow" 3971f1932bSmartinboehme 40af7bc39bSStanislav Gatev namespace clang { 41af7bc39bSStanislav Gatev namespace dataflow { 42af7bc39bSStanislav Gatev 43208c25fcSYitzhak Mandelbaum // FIXME: convert these to parameters of the analysis or environment. Current 44208c25fcSYitzhak Mandelbaum // settings have been experimentaly validated, but only for a particular 45208c25fcSYitzhak Mandelbaum // analysis. 46208c25fcSYitzhak Mandelbaum static constexpr int MaxCompositeValueDepth = 3; 47208c25fcSYitzhak Mandelbaum static constexpr int MaxCompositeValueSize = 1000; 48208c25fcSYitzhak Mandelbaum 49af7bc39bSStanislav Gatev /// Returns a map consisting of key-value entries that are present in both maps. 50c4c59192Smartinboehme static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc( 51c4c59192Smartinboehme const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1, 52c4c59192Smartinboehme const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) { 53c4c59192Smartinboehme llvm::DenseMap<const ValueDecl *, StorageLocation *> Result; 54c4c59192Smartinboehme for (auto &Entry : DeclToLoc1) { 55c4c59192Smartinboehme auto It = DeclToLoc2.find(Entry.first); 56c4c59192Smartinboehme if (It != DeclToLoc2.end() && Entry.second == It->second) 57af7bc39bSStanislav Gatev Result.insert({Entry.first, Entry.second}); 58af7bc39bSStanislav Gatev } 59af7bc39bSStanislav Gatev return Result; 60af7bc39bSStanislav Gatev } 61af7bc39bSStanislav Gatev 62d5aecf0cSmartinboehme // Performs a join on either `ExprToLoc` or `ExprToVal`. 63d5aecf0cSmartinboehme // The maps must be consistent in the sense that any entries for the same 64d5aecf0cSmartinboehme // expression must map to the same location / value. This is the case if we are 65d5aecf0cSmartinboehme // performing a join for control flow within a full-expression (which is the 66d5aecf0cSmartinboehme // only case when this function should be used). 67*65c36179SCongcong Cai template <typename MapT> 68*65c36179SCongcong Cai static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) { 69d5aecf0cSmartinboehme MapT Result = Map1; 70d5aecf0cSmartinboehme 71d5aecf0cSmartinboehme for (const auto &Entry : Map2) { 72d5aecf0cSmartinboehme [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry); 73d5aecf0cSmartinboehme // If there was an existing entry, its value should be the same as for the 74d5aecf0cSmartinboehme // entry we were trying to insert. 75d5aecf0cSmartinboehme assert(It->second == Entry.second); 76d5aecf0cSmartinboehme } 77d5aecf0cSmartinboehme 78d5aecf0cSmartinboehme return Result; 79d5aecf0cSmartinboehme } 80d5aecf0cSmartinboehme 8180f0dc3aSYitzhak Mandelbaum // Whether to consider equivalent two values with an unknown relation. 8280f0dc3aSYitzhak Mandelbaum // 8380f0dc3aSYitzhak Mandelbaum // FIXME: this function is a hack enabling unsoundness to support 8480f0dc3aSYitzhak Mandelbaum // convergence. Once we have widening support for the reference/pointer and 8580f0dc3aSYitzhak Mandelbaum // struct built-in models, this should be unconditionally `false` (and inlined 8680f0dc3aSYitzhak Mandelbaum // as such at its call sites). 8780f0dc3aSYitzhak Mandelbaum static bool equateUnknownValues(Value::Kind K) { 8880f0dc3aSYitzhak Mandelbaum switch (K) { 8980f0dc3aSYitzhak Mandelbaum case Value::Kind::Integer: 9080f0dc3aSYitzhak Mandelbaum case Value::Kind::Pointer: 9180f0dc3aSYitzhak Mandelbaum return true; 9280f0dc3aSYitzhak Mandelbaum default: 9380f0dc3aSYitzhak Mandelbaum return false; 9480f0dc3aSYitzhak Mandelbaum } 9580f0dc3aSYitzhak Mandelbaum } 9680f0dc3aSYitzhak Mandelbaum 9784dd12b2SYitzhak Mandelbaum static bool compareDistinctValues(QualType Type, Value &Val1, 9884dd12b2SYitzhak Mandelbaum const Environment &Env1, Value &Val2, 9984dd12b2SYitzhak Mandelbaum const Environment &Env2, 10084dd12b2SYitzhak Mandelbaum Environment::ValueModel &Model) { 10184dd12b2SYitzhak Mandelbaum // Note: Potentially costly, but, for booleans, we could check whether both 10284dd12b2SYitzhak Mandelbaum // can be proven equivalent in their respective environments. 10384dd12b2SYitzhak Mandelbaum 10484dd12b2SYitzhak Mandelbaum // FIXME: move the reference/pointers logic from `areEquivalentValues` to here 10584dd12b2SYitzhak Mandelbaum // and implement separate, join/widen specific handling for 10684dd12b2SYitzhak Mandelbaum // reference/pointers. 10784dd12b2SYitzhak Mandelbaum switch (Model.compare(Type, Val1, Env1, Val2, Env2)) { 10884dd12b2SYitzhak Mandelbaum case ComparisonResult::Same: 10984dd12b2SYitzhak Mandelbaum return true; 11084dd12b2SYitzhak Mandelbaum case ComparisonResult::Different: 11184dd12b2SYitzhak Mandelbaum return false; 11284dd12b2SYitzhak Mandelbaum case ComparisonResult::Unknown: 11380f0dc3aSYitzhak Mandelbaum return equateUnknownValues(Val1.getKind()); 11484dd12b2SYitzhak Mandelbaum } 11584dd12b2SYitzhak Mandelbaum llvm_unreachable("All cases covered in switch"); 11684dd12b2SYitzhak Mandelbaum } 11784dd12b2SYitzhak Mandelbaum 118672fb27bSYitzhak Mandelbaum /// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`, 119672fb27bSYitzhak Mandelbaum /// respectively, of the same type `Type`. Joining generally produces a single 12001db1036SYitzhak Mandelbaum /// value that (soundly) approximates the two inputs, although the actual 12101db1036SYitzhak Mandelbaum /// meaning depends on `Model`. 122672fb27bSYitzhak Mandelbaum static Value *joinDistinctValues(QualType Type, Value &Val1, 12384dd12b2SYitzhak Mandelbaum const Environment &Env1, Value &Val2, 12437b4782eSYitzhak Mandelbaum const Environment &Env2, 125672fb27bSYitzhak Mandelbaum Environment &JoinedEnv, 12601db1036SYitzhak Mandelbaum Environment::ValueModel &Model) { 12701db1036SYitzhak Mandelbaum // Join distinct boolean values preserving information about the constraints 128955a05a2SStanislav Gatev // in the respective path conditions. 129daa316bcSYitzhak Mandelbaum if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) { 130daa316bcSYitzhak Mandelbaum // FIXME: Checking both values should be unnecessary, since they should have 131daa316bcSYitzhak Mandelbaum // a consistent shape. However, right now we can end up with BoolValue's in 132daa316bcSYitzhak Mandelbaum // integer-typed variables due to our incorrect handling of 133daa316bcSYitzhak Mandelbaum // boolean-to-integer casts (we just propagate the BoolValue to the result 134daa316bcSYitzhak Mandelbaum // of the cast). So, a join can encounter an integer in one branch but a 135daa316bcSYitzhak Mandelbaum // bool in the other. 136daa316bcSYitzhak Mandelbaum // For example: 137daa316bcSYitzhak Mandelbaum // ``` 138eda2eaabSJun Zhang // std::optional<bool> o; 139eda2eaabSJun Zhang // int x; 140daa316bcSYitzhak Mandelbaum // if (o.has_value()) 141eda2eaabSJun Zhang // x = o.value(); 142daa316bcSYitzhak Mandelbaum // ``` 143fc9821a8SSam McCall auto &Expr1 = cast<BoolValue>(Val1).formula(); 144fc9821a8SSam McCall auto &Expr2 = cast<BoolValue>(Val2).formula(); 145672fb27bSYitzhak Mandelbaum auto &A = JoinedEnv.arena(); 146672fb27bSYitzhak Mandelbaum auto &JoinedVal = A.makeAtomRef(A.makeAtom()); 147672fb27bSYitzhak Mandelbaum JoinedEnv.assume( 148fc9821a8SSam McCall A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()), 149672fb27bSYitzhak Mandelbaum A.makeEquals(JoinedVal, Expr1)), 150fc9821a8SSam McCall A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()), 151672fb27bSYitzhak Mandelbaum A.makeEquals(JoinedVal, Expr2)))); 152672fb27bSYitzhak Mandelbaum return &A.makeBoolValue(JoinedVal); 15301db1036SYitzhak Mandelbaum } 15401db1036SYitzhak Mandelbaum 155e8fce958Smartinboehme Value *JoinedVal = JoinedEnv.createValue(Type); 156672fb27bSYitzhak Mandelbaum if (JoinedVal) 157672fb27bSYitzhak Mandelbaum Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv); 15801db1036SYitzhak Mandelbaum 159672fb27bSYitzhak Mandelbaum return JoinedVal; 16001db1036SYitzhak Mandelbaum } 16101db1036SYitzhak Mandelbaum 162bbd259afSYitzhak Mandelbaum static WidenResult widenDistinctValues(QualType Type, Value &Prev, 163bbd259afSYitzhak Mandelbaum const Environment &PrevEnv, 164bbd259afSYitzhak Mandelbaum Value &Current, Environment &CurrentEnv, 16584dd12b2SYitzhak Mandelbaum Environment::ValueModel &Model) { 16684dd12b2SYitzhak Mandelbaum // Boolean-model widening. 167b9208ce3Smartinboehme if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) { 168b9208ce3Smartinboehme // FIXME: Checking both values should be unnecessary, but we can currently 169b9208ce3Smartinboehme // end up with `BoolValue`s in integer-typed variables. See comment in 170b9208ce3Smartinboehme // `joinDistinctValues()` for details. 171b9208ce3Smartinboehme auto &PrevBool = cast<BoolValue>(Prev); 172b9208ce3Smartinboehme auto &CurBool = cast<BoolValue>(Current); 173b9208ce3Smartinboehme 17484dd12b2SYitzhak Mandelbaum if (isa<TopBoolValue>(Prev)) 175bbd259afSYitzhak Mandelbaum // Safe to return `Prev` here, because Top is never dependent on the 176bbd259afSYitzhak Mandelbaum // environment. 177bbd259afSYitzhak Mandelbaum return {&Prev, LatticeEffect::Unchanged}; 1785bd643e1Smartinboehme 1795bd643e1Smartinboehme // We may need to widen to Top, but before we do so, check whether both 1805bd643e1Smartinboehme // values are implied to be either true or false in the current environment. 1815bd643e1Smartinboehme // In that case, we can simply return a literal instead. 182b9208ce3Smartinboehme bool TruePrev = PrevEnv.proves(PrevBool.formula()); 1835bd643e1Smartinboehme bool TrueCur = CurrentEnv.proves(CurBool.formula()); 1845bd643e1Smartinboehme if (TruePrev && TrueCur) 185bbd259afSYitzhak Mandelbaum return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged}; 1865bd643e1Smartinboehme if (!TruePrev && !TrueCur && 187b9208ce3Smartinboehme PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) && 1885bd643e1Smartinboehme CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) 189bbd259afSYitzhak Mandelbaum return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged}; 1905bd643e1Smartinboehme 191bbd259afSYitzhak Mandelbaum return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed}; 19284dd12b2SYitzhak Mandelbaum } 19384dd12b2SYitzhak Mandelbaum 19484dd12b2SYitzhak Mandelbaum // FIXME: Add other built-in model widening. 19584dd12b2SYitzhak Mandelbaum 19684dd12b2SYitzhak Mandelbaum // Custom-model widening. 197bbd259afSYitzhak Mandelbaum if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) 198bbd259afSYitzhak Mandelbaum return *Result; 19984dd12b2SYitzhak Mandelbaum 200bbd259afSYitzhak Mandelbaum return {&Current, equateUnknownValues(Prev.getKind()) 201bbd259afSYitzhak Mandelbaum ? LatticeEffect::Unchanged 202bbd259afSYitzhak Mandelbaum : LatticeEffect::Changed}; 20384dd12b2SYitzhak Mandelbaum } 20484dd12b2SYitzhak Mandelbaum 205330d5bcbSMartin Braenne // Returns whether the values in `Map1` and `Map2` compare equal for those 206330d5bcbSMartin Braenne // keys that `Map1` and `Map2` have in common. 207330d5bcbSMartin Braenne template <typename Key> 208*65c36179SCongcong Cai static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1, 209330d5bcbSMartin Braenne const llvm::MapVector<Key, Value *> &Map2, 210*65c36179SCongcong Cai const Environment &Env1, 211*65c36179SCongcong Cai const Environment &Env2, 212330d5bcbSMartin Braenne Environment::ValueModel &Model) { 213330d5bcbSMartin Braenne for (auto &Entry : Map1) { 214330d5bcbSMartin Braenne Key K = Entry.first; 215330d5bcbSMartin Braenne assert(K != nullptr); 216330d5bcbSMartin Braenne 217330d5bcbSMartin Braenne Value *Val = Entry.second; 218330d5bcbSMartin Braenne assert(Val != nullptr); 219330d5bcbSMartin Braenne 220330d5bcbSMartin Braenne auto It = Map2.find(K); 221330d5bcbSMartin Braenne if (It == Map2.end()) 222330d5bcbSMartin Braenne continue; 223330d5bcbSMartin Braenne assert(It->second != nullptr); 224330d5bcbSMartin Braenne 225330d5bcbSMartin Braenne if (!areEquivalentValues(*Val, *It->second) && 226330d5bcbSMartin Braenne !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2, 227330d5bcbSMartin Braenne Model)) 228330d5bcbSMartin Braenne return false; 229330d5bcbSMartin Braenne } 230330d5bcbSMartin Braenne 231330d5bcbSMartin Braenne return true; 232330d5bcbSMartin Braenne } 233330d5bcbSMartin Braenne 234c4c59192Smartinboehme // Perform a join on two `LocToVal` maps. 235c4c59192Smartinboehme static llvm::MapVector<const StorageLocation *, Value *> 236c4c59192Smartinboehme joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal, 237c4c59192Smartinboehme const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2, 238330d5bcbSMartin Braenne const Environment &Env1, const Environment &Env2, 239330d5bcbSMartin Braenne Environment &JoinedEnv, Environment::ValueModel &Model) { 240c4c59192Smartinboehme llvm::MapVector<const StorageLocation *, Value *> Result; 241c4c59192Smartinboehme for (auto &Entry : LocToVal) { 242c4c59192Smartinboehme const StorageLocation *Loc = Entry.first; 243c4c59192Smartinboehme assert(Loc != nullptr); 244330d5bcbSMartin Braenne 245330d5bcbSMartin Braenne Value *Val = Entry.second; 246330d5bcbSMartin Braenne assert(Val != nullptr); 247330d5bcbSMartin Braenne 248c4c59192Smartinboehme auto It = LocToVal2.find(Loc); 249c4c59192Smartinboehme if (It == LocToVal2.end()) 250330d5bcbSMartin Braenne continue; 251330d5bcbSMartin Braenne assert(It->second != nullptr); 252330d5bcbSMartin Braenne 2539ba6961cSmartinboehme if (Value *JoinedVal = Environment::joinValues( 2549ba6961cSmartinboehme Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) { 255672fb27bSYitzhak Mandelbaum Result.insert({Loc, JoinedVal}); 256330d5bcbSMartin Braenne } 257330d5bcbSMartin Braenne } 258330d5bcbSMartin Braenne 259c4c59192Smartinboehme return Result; 260330d5bcbSMartin Braenne } 261330d5bcbSMartin Braenne 262330d5bcbSMartin Braenne // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either 263330d5bcbSMartin Braenne // `const StorageLocation *` or `const Expr *`. 264330d5bcbSMartin Braenne template <typename Key> 265*65c36179SCongcong Cai static llvm::MapVector<Key, Value *> 266330d5bcbSMartin Braenne widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, 267330d5bcbSMartin Braenne const llvm::MapVector<Key, Value *> &PrevMap, 268330d5bcbSMartin Braenne Environment &CurEnv, const Environment &PrevEnv, 269bbd259afSYitzhak Mandelbaum Environment::ValueModel &Model, LatticeEffect &Effect) { 270330d5bcbSMartin Braenne llvm::MapVector<Key, Value *> WidenedMap; 271330d5bcbSMartin Braenne for (auto &Entry : CurMap) { 272330d5bcbSMartin Braenne Key K = Entry.first; 273330d5bcbSMartin Braenne assert(K != nullptr); 274330d5bcbSMartin Braenne 275330d5bcbSMartin Braenne Value *Val = Entry.second; 276330d5bcbSMartin Braenne assert(Val != nullptr); 277330d5bcbSMartin Braenne 278330d5bcbSMartin Braenne auto PrevIt = PrevMap.find(K); 279330d5bcbSMartin Braenne if (PrevIt == PrevMap.end()) 280330d5bcbSMartin Braenne continue; 281330d5bcbSMartin Braenne assert(PrevIt->second != nullptr); 282330d5bcbSMartin Braenne 283330d5bcbSMartin Braenne if (areEquivalentValues(*Val, *PrevIt->second)) { 284330d5bcbSMartin Braenne WidenedMap.insert({K, Val}); 285330d5bcbSMartin Braenne continue; 286330d5bcbSMartin Braenne } 287330d5bcbSMartin Braenne 288bbd259afSYitzhak Mandelbaum auto [WidenedVal, ValEffect] = widenDistinctValues( 289bbd259afSYitzhak Mandelbaum K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model); 290bbd259afSYitzhak Mandelbaum WidenedMap.insert({K, WidenedVal}); 291bbd259afSYitzhak Mandelbaum if (ValEffect == LatticeEffect::Changed) 292bbd259afSYitzhak Mandelbaum Effect = LatticeEffect::Changed; 293330d5bcbSMartin Braenne } 294330d5bcbSMartin Braenne 295330d5bcbSMartin Braenne return WidenedMap; 296330d5bcbSMartin Braenne } 297330d5bcbSMartin Braenne 29871f1932bSmartinboehme namespace { 29971f1932bSmartinboehme 30071f1932bSmartinboehme // Visitor that builds a map from record prvalues to result objects. 30180d9ae9cSSamira Bazuzi // For each result object that it encounters, it propagates the storage location 30280d9ae9cSSamira Bazuzi // of the result object to all record prvalues that can initialize it. 303dde802b1SSirraide class ResultObjectVisitor : public AnalysisASTVisitor { 30471f1932bSmartinboehme public: 30571f1932bSmartinboehme // `ResultObjectMap` will be filled with a map from record prvalues to result 30680d9ae9cSSamira Bazuzi // object. If this visitor will traverse a function that returns a record by 30780d9ae9cSSamira Bazuzi // value, `LocForRecordReturnVal` is the location to which this record should 30880d9ae9cSSamira Bazuzi // be written; otherwise, it is null. 30971f1932bSmartinboehme explicit ResultObjectVisitor( 31071f1932bSmartinboehme llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap, 31171f1932bSmartinboehme RecordStorageLocation *LocForRecordReturnVal, 31271f1932bSmartinboehme DataflowAnalysisContext &DACtx) 31371f1932bSmartinboehme : ResultObjectMap(ResultObjectMap), 31471f1932bSmartinboehme LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {} 31571f1932bSmartinboehme 31671f1932bSmartinboehme // Traverse all member and base initializers of `Ctor`. This function is not 31771f1932bSmartinboehme // called by `RecursiveASTVisitor`; it should be called manually if we are 31871f1932bSmartinboehme // analyzing a constructor. `ThisPointeeLoc` is the storage location that 31971f1932bSmartinboehme // `this` points to. 320dde802b1SSirraide void traverseConstructorInits(const CXXConstructorDecl *Ctor, 32171f1932bSmartinboehme RecordStorageLocation *ThisPointeeLoc) { 32271f1932bSmartinboehme assert(ThisPointeeLoc != nullptr); 32371f1932bSmartinboehme for (const CXXCtorInitializer *Init : Ctor->inits()) { 32471f1932bSmartinboehme Expr *InitExpr = Init->getInit(); 32571f1932bSmartinboehme if (FieldDecl *Field = Init->getMember(); 32671f1932bSmartinboehme Field != nullptr && Field->getType()->isRecordType()) { 32771f1932bSmartinboehme PropagateResultObject(InitExpr, cast<RecordStorageLocation>( 32871f1932bSmartinboehme ThisPointeeLoc->getChild(*Field))); 32971f1932bSmartinboehme } else if (Init->getBaseClass()) { 33071f1932bSmartinboehme PropagateResultObject(InitExpr, ThisPointeeLoc); 33171f1932bSmartinboehme } 33271f1932bSmartinboehme 33371f1932bSmartinboehme // Ensure that any result objects within `InitExpr` (e.g. temporaries) 33471f1932bSmartinboehme // are also propagated to the prvalues that initialize them. 33571f1932bSmartinboehme TraverseStmt(InitExpr); 33671f1932bSmartinboehme 33771f1932bSmartinboehme // If this is a `CXXDefaultInitExpr`, also propagate any result objects 33871f1932bSmartinboehme // within the default expression. 33971f1932bSmartinboehme if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr)) 34071f1932bSmartinboehme TraverseStmt(DefaultInit->getExpr()); 34171f1932bSmartinboehme } 34271f1932bSmartinboehme } 34371f1932bSmartinboehme 344dde802b1SSirraide bool VisitVarDecl(VarDecl *VD) override { 34571f1932bSmartinboehme if (VD->getType()->isRecordType() && VD->hasInit()) 34671f1932bSmartinboehme PropagateResultObject( 34771f1932bSmartinboehme VD->getInit(), 34871f1932bSmartinboehme &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD))); 34971f1932bSmartinboehme return true; 35071f1932bSmartinboehme } 35171f1932bSmartinboehme 352dde802b1SSirraide bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override { 35371f1932bSmartinboehme if (MTE->getType()->isRecordType()) 35471f1932bSmartinboehme PropagateResultObject( 35571f1932bSmartinboehme MTE->getSubExpr(), 35671f1932bSmartinboehme &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE))); 35771f1932bSmartinboehme return true; 35871f1932bSmartinboehme } 35971f1932bSmartinboehme 360dde802b1SSirraide bool VisitReturnStmt(ReturnStmt *Return) override { 36171f1932bSmartinboehme Expr *RetValue = Return->getRetValue(); 36271f1932bSmartinboehme if (RetValue != nullptr && RetValue->getType()->isRecordType() && 36371f1932bSmartinboehme RetValue->isPRValue()) 36471f1932bSmartinboehme PropagateResultObject(RetValue, LocForRecordReturnVal); 36571f1932bSmartinboehme return true; 36671f1932bSmartinboehme } 36771f1932bSmartinboehme 368dde802b1SSirraide bool VisitExpr(Expr *E) override { 36971f1932bSmartinboehme // Clang's AST can have record-type prvalues without a result object -- for 37071f1932bSmartinboehme // example as full-expressions contained in a compound statement or as 37171f1932bSmartinboehme // arguments of call expressions. We notice this if we get here and a 37271f1932bSmartinboehme // storage location has not yet been associated with `E`. In this case, 37371f1932bSmartinboehme // treat this as if it was a `MaterializeTemporaryExpr`. 37471f1932bSmartinboehme if (E->isPRValue() && E->getType()->isRecordType() && 37571f1932bSmartinboehme !ResultObjectMap.contains(E)) 37671f1932bSmartinboehme PropagateResultObject( 37771f1932bSmartinboehme E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E))); 37871f1932bSmartinboehme return true; 37971f1932bSmartinboehme } 38071f1932bSmartinboehme 381ca7d9442Smartinboehme void 382ca7d9442Smartinboehme PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList, 383ca7d9442Smartinboehme RecordStorageLocation *Loc) { 384ca7d9442Smartinboehme for (auto [Base, Init] : InitList.base_inits()) { 385ca7d9442Smartinboehme assert(Base->getType().getCanonicalType() == 386ca7d9442Smartinboehme Init->getType().getCanonicalType()); 387ca7d9442Smartinboehme 388ca7d9442Smartinboehme // Storage location for the base class is the same as that of the 389ca7d9442Smartinboehme // derived class because we "flatten" the object hierarchy and put all 390ca7d9442Smartinboehme // fields in `RecordStorageLocation` of the derived class. 391ca7d9442Smartinboehme PropagateResultObject(Init, Loc); 392ca7d9442Smartinboehme } 393ca7d9442Smartinboehme 394ca7d9442Smartinboehme for (auto [Field, Init] : InitList.field_inits()) { 395ca7d9442Smartinboehme // Fields of non-record type are handled in 396ca7d9442Smartinboehme // `TransferVisitor::VisitInitListExpr()`. 397ca7d9442Smartinboehme if (Field->getType()->isRecordType()) 39814122106Smartinboehme PropagateResultObject( 39914122106Smartinboehme Init, cast<RecordStorageLocation>(Loc->getChild(*Field))); 400ca7d9442Smartinboehme } 401ca7d9442Smartinboehme } 402ca7d9442Smartinboehme 40371f1932bSmartinboehme // Assigns `Loc` as the result object location of `E`, then propagates the 40471f1932bSmartinboehme // location to all lower-level prvalues that initialize the same object as 40571f1932bSmartinboehme // `E` (or one of its base classes or member variables). 40671f1932bSmartinboehme void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) { 40771f1932bSmartinboehme if (!E->isPRValue() || !E->getType()->isRecordType()) { 40871f1932bSmartinboehme assert(false); 40971f1932bSmartinboehme // Ensure we don't propagate the result object if we hit this in a 41071f1932bSmartinboehme // release build. 41171f1932bSmartinboehme return; 41271f1932bSmartinboehme } 41371f1932bSmartinboehme 41471f1932bSmartinboehme ResultObjectMap[E] = Loc; 41571f1932bSmartinboehme 41671f1932bSmartinboehme // The following AST node kinds are "original initializers": They are the 41771f1932bSmartinboehme // lowest-level AST node that initializes a given object, and nothing 41871f1932bSmartinboehme // below them can initialize the same object (or part of it). 419b5f2cecfSmartinboehme if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) || 4203fed312dSSamira Bazuzi isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) || 42149cb1701SPasquale Riello isa<AtomicExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) || 422b5f2cecfSmartinboehme // We treat `BuiltinBitCastExpr` as an "original initializer" too as 423b5f2cecfSmartinboehme // it may not even be casting from a record type -- and even if it is, 424b5f2cecfSmartinboehme // the two objects are in general of unrelated type. 425b5f2cecfSmartinboehme isa<BuiltinBitCastExpr>(E)) { 42671f1932bSmartinboehme return; 42771f1932bSmartinboehme } 428b5f2cecfSmartinboehme if (auto *Op = dyn_cast<BinaryOperator>(E); 429b5f2cecfSmartinboehme Op && Op->getOpcode() == BO_Cmp) { 430b5f2cecfSmartinboehme // Builtin `<=>` returns a `std::strong_ordering` object. 4313c6f91e5Smartinboehme return; 4323c6f91e5Smartinboehme } 433b5f2cecfSmartinboehme 434b5f2cecfSmartinboehme if (auto *InitList = dyn_cast<InitListExpr>(E)) { 43571f1932bSmartinboehme if (!InitList->isSemanticForm()) 43671f1932bSmartinboehme return; 43771f1932bSmartinboehme if (InitList->isTransparent()) { 43871f1932bSmartinboehme PropagateResultObject(InitList->getInit(0), Loc); 43971f1932bSmartinboehme return; 44071f1932bSmartinboehme } 44171f1932bSmartinboehme 442ca7d9442Smartinboehme PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList), 443ca7d9442Smartinboehme Loc); 444ca7d9442Smartinboehme return; 44571f1932bSmartinboehme } 44671f1932bSmartinboehme 447ca7d9442Smartinboehme if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) { 448ca7d9442Smartinboehme PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList), 449ca7d9442Smartinboehme Loc); 45071f1932bSmartinboehme return; 45171f1932bSmartinboehme } 452b5f2cecfSmartinboehme 453b5f2cecfSmartinboehme if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) { 454b5f2cecfSmartinboehme PropagateResultObject(Op->getRHS(), Loc); 455b5f2cecfSmartinboehme return; 456b5f2cecfSmartinboehme } 457b5f2cecfSmartinboehme 458b5f2cecfSmartinboehme if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) { 459b5f2cecfSmartinboehme PropagateResultObject(Cond->getTrueExpr(), Loc); 460b5f2cecfSmartinboehme PropagateResultObject(Cond->getFalseExpr(), Loc); 461b5f2cecfSmartinboehme return; 462b5f2cecfSmartinboehme } 463b5f2cecfSmartinboehme 464b5f2cecfSmartinboehme if (auto *SE = dyn_cast<StmtExpr>(E)) { 465b5f2cecfSmartinboehme PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc); 466b5f2cecfSmartinboehme return; 467b5f2cecfSmartinboehme } 468b5f2cecfSmartinboehme 4693fed312dSSamira Bazuzi if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) { 4703fed312dSSamira Bazuzi PropagateResultObject(DIE->getExpr(), Loc); 4713fed312dSSamira Bazuzi return; 4723fed312dSSamira Bazuzi } 4733fed312dSSamira Bazuzi 474b5f2cecfSmartinboehme // All other expression nodes that propagate a record prvalue should have 475b5f2cecfSmartinboehme // exactly one child. 47671f1932bSmartinboehme SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end()); 47771f1932bSmartinboehme LLVM_DEBUG({ 47871f1932bSmartinboehme if (Children.size() != 1) 47971f1932bSmartinboehme E->dump(); 48071f1932bSmartinboehme }); 48171f1932bSmartinboehme assert(Children.size() == 1); 48271f1932bSmartinboehme for (Stmt *S : Children) 48371f1932bSmartinboehme PropagateResultObject(cast<Expr>(S), Loc); 48471f1932bSmartinboehme } 48571f1932bSmartinboehme 48671f1932bSmartinboehme private: 48771f1932bSmartinboehme llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap; 48871f1932bSmartinboehme RecordStorageLocation *LocForRecordReturnVal; 48971f1932bSmartinboehme DataflowAnalysisContext &DACtx; 49071f1932bSmartinboehme }; 49171f1932bSmartinboehme 49271f1932bSmartinboehme } // namespace 49371f1932bSmartinboehme 49480d9ae9cSSamira Bazuzi void Environment::initialize() { 49580d9ae9cSSamira Bazuzi if (InitialTargetStmt == nullptr) 49680d9ae9cSSamira Bazuzi return; 49771f2ec2dSmartinboehme 49880d9ae9cSSamira Bazuzi if (InitialTargetFunc == nullptr) { 49980d9ae9cSSamira Bazuzi initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt)); 50080d9ae9cSSamira Bazuzi ResultObjectMap = 50180d9ae9cSSamira Bazuzi std::make_shared<PrValueToResultObject>(buildResultObjectMap( 50280d9ae9cSSamira Bazuzi DACtx, InitialTargetStmt, getThisPointeeStorageLocation(), 50380d9ae9cSSamira Bazuzi /*LocForRecordReturnValue=*/nullptr)); 50480d9ae9cSSamira Bazuzi return; 50571f2ec2dSmartinboehme } 50671f2ec2dSmartinboehme 50780d9ae9cSSamira Bazuzi initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc)); 50871f2ec2dSmartinboehme 50980d9ae9cSSamira Bazuzi for (const auto *ParamDecl : InitialTargetFunc->parameters()) { 51071f2ec2dSmartinboehme assert(ParamDecl != nullptr); 51171f2ec2dSmartinboehme setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); 51271f2ec2dSmartinboehme } 51371f1932bSmartinboehme 51480d9ae9cSSamira Bazuzi if (InitialTargetFunc->getReturnType()->isRecordType()) 51571f1932bSmartinboehme LocForRecordReturnVal = &cast<RecordStorageLocation>( 51680d9ae9cSSamira Bazuzi createStorageLocation(InitialTargetFunc->getReturnType())); 51771f2ec2dSmartinboehme 51880d9ae9cSSamira Bazuzi if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) { 51971f2ec2dSmartinboehme auto *Parent = MethodDecl->getParent(); 52071f2ec2dSmartinboehme assert(Parent != nullptr); 52171f2ec2dSmartinboehme 52271f2ec2dSmartinboehme if (Parent->isLambda()) { 5234c4ea249Ssmanna12 for (const auto &Capture : Parent->captures()) { 52471f2ec2dSmartinboehme if (Capture.capturesVariable()) { 52571f2ec2dSmartinboehme const auto *VarDecl = Capture.getCapturedVar(); 52671f2ec2dSmartinboehme assert(VarDecl != nullptr); 52771f2ec2dSmartinboehme setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr)); 52871f2ec2dSmartinboehme } else if (Capture.capturesThis()) { 52983c2bfdaSSamira Bazuzi if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) { 53083c2bfdaSSamira Bazuzi const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor); 53171f2ec2dSmartinboehme QualType ThisPointeeType = 53271f2ec2dSmartinboehme SurroundingMethodDecl->getFunctionObjectParameterType(); 53371f2ec2dSmartinboehme setThisPointeeStorageLocation( 5347a6c2628Smartinboehme cast<RecordStorageLocation>(createObject(ThisPointeeType))); 53583c2bfdaSSamira Bazuzi } else if (auto *FieldBeingInitialized = 53683c2bfdaSSamira Bazuzi dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) { 53783c2bfdaSSamira Bazuzi // This is in a field initializer, rather than a method. 53883c2bfdaSSamira Bazuzi setThisPointeeStorageLocation( 53983c2bfdaSSamira Bazuzi cast<RecordStorageLocation>(createObject(QualType( 54083c2bfdaSSamira Bazuzi FieldBeingInitialized->getParent()->getTypeForDecl(), 0)))); 54183c2bfdaSSamira Bazuzi } else { 54283c2bfdaSSamira Bazuzi assert(false && "Unexpected this-capturing lambda context."); 54383c2bfdaSSamira Bazuzi } 54471f2ec2dSmartinboehme } 54571f2ec2dSmartinboehme } 54671f2ec2dSmartinboehme } else if (MethodDecl->isImplicitObjectMemberFunction()) { 54771f2ec2dSmartinboehme QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType(); 5482d539db2Smartinboehme auto &ThisLoc = 5492d539db2Smartinboehme cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType)); 5502d539db2Smartinboehme setThisPointeeStorageLocation(ThisLoc); 5512d539db2Smartinboehme // Initialize fields of `*this` with values, but only if we're not 5522d539db2Smartinboehme // analyzing a constructor; after all, it's the constructor's job to do 5532d539db2Smartinboehme // this (and we want to be able to test that). 5542d539db2Smartinboehme if (!isa<CXXConstructorDecl>(MethodDecl)) 5552d539db2Smartinboehme initializeFieldsWithValues(ThisLoc); 55671f2ec2dSmartinboehme } 55771f2ec2dSmartinboehme } 55871f1932bSmartinboehme 55971f1932bSmartinboehme // We do this below the handling of `CXXMethodDecl` above so that we can 56071f1932bSmartinboehme // be sure that the storage location for `this` has been set. 56180d9ae9cSSamira Bazuzi ResultObjectMap = 56280d9ae9cSSamira Bazuzi std::make_shared<PrValueToResultObject>(buildResultObjectMap( 56380d9ae9cSSamira Bazuzi DACtx, InitialTargetFunc, getThisPointeeStorageLocation(), 56471f1932bSmartinboehme LocForRecordReturnVal)); 56571f2ec2dSmartinboehme } 56671f2ec2dSmartinboehme 56780d9ae9cSSamira Bazuzi // FIXME: Add support for resetting globals after function calls to enable the 56880d9ae9cSSamira Bazuzi // implementation of sound analyses. 569ce0ab9d1SMartin Braenne 57080d9ae9cSSamira Bazuzi void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) { 571ce0ab9d1SMartin Braenne // These have to be added before the lines that follow to ensure that 572ce0ab9d1SMartin Braenne // `create*` work correctly for structs. 5739ec8c961SSamira Bazuzi DACtx->addModeledFields(Referenced.Fields); 574ce0ab9d1SMartin Braenne 5759ec8c961SSamira Bazuzi for (const VarDecl *D : Referenced.Globals) { 5769940fac7SMartin Braenne if (getStorageLocation(*D) != nullptr) 57701ccf7b3SYitzhak Mandelbaum continue; 5786d768548SMartin Braenne 57971f1932bSmartinboehme // We don't run transfer functions on the initializers of global variables, 58071f1932bSmartinboehme // so they won't be associated with a value or storage location. We 58180d9ae9cSSamira Bazuzi // therefore intentionally don't pass an initializer to `createObject()`; in 58280d9ae9cSSamira Bazuzi // particular, this ensures that `createObject()` will initialize the fields 58380d9ae9cSSamira Bazuzi // of record-type variables with values. 58471f1932bSmartinboehme setStorageLocation(*D, createObject(*D, nullptr)); 58503dff121SStanislav Gatev } 586d9e71733SMartin Braenne 5879ec8c961SSamira Bazuzi for (const FunctionDecl *FD : Referenced.Functions) { 5889940fac7SMartin Braenne if (getStorageLocation(*FD) != nullptr) 589d9e71733SMartin Braenne continue; 59071f1932bSmartinboehme auto &Loc = createStorageLocation(*FD); 591d9e71733SMartin Braenne setStorageLocation(*FD, Loc); 592d9e71733SMartin Braenne } 59303dff121SStanislav Gatev } 59403dff121SStanislav Gatev 595c2bb6807SSam McCall Environment Environment::fork() const { 596c2bb6807SSam McCall Environment Copy(*this); 597fc9821a8SSam McCall Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken); 598c2bb6807SSam McCall return Copy; 599955a05a2SStanislav Gatev } 600955a05a2SStanislav Gatev 6012efc8f8dSSam Estep bool Environment::canDescend(unsigned MaxDepth, 60280d9ae9cSSamira Bazuzi const FunctionDecl *Callee) const { 60380d9ae9cSSamira Bazuzi return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee); 6042efc8f8dSSam Estep } 6052efc8f8dSSam Estep 606300fbf56SSam Estep Environment Environment::pushCall(const CallExpr *Call) const { 607300fbf56SSam Estep Environment Env(*this); 608eb91fd5cSSam Estep 609eb91fd5cSSam Estep if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) { 610eb91fd5cSSam Estep if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { 6110b12efc7SYitzhak Mandelbaum if (!isa<CXXThisExpr>(Arg)) 612f76f6674SMartin Braenne Env.ThisPointeeLoc = 6139ecdbe38SMartin Braenne cast<RecordStorageLocation>(getStorageLocation(*Arg)); 6140b12efc7SYitzhak Mandelbaum // Otherwise (when the argument is `this`), retain the current 6150b12efc7SYitzhak Mandelbaum // environment's `ThisPointeeLoc`. 616eb91fd5cSSam Estep } 617eb91fd5cSSam Estep } 6182cb51449SWei Yi Tee 61971f1932bSmartinboehme if (Call->getType()->isRecordType() && Call->isPRValue()) 62071f1932bSmartinboehme Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); 62171f1932bSmartinboehme 622eb91fd5cSSam Estep Env.pushCallInternal(Call->getDirectCallee(), 623a3c248dbSserge-sans-paille llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 624eb91fd5cSSam Estep 625eb91fd5cSSam Estep return Env; 626eb91fd5cSSam Estep } 627eb91fd5cSSam Estep 628eb91fd5cSSam Estep Environment Environment::pushCall(const CXXConstructExpr *Call) const { 629eb91fd5cSSam Estep Environment Env(*this); 630eb91fd5cSSam Estep 63144f98d01SMartin Braenne Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); 63271f1932bSmartinboehme Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); 633eb91fd5cSSam Estep 634eb91fd5cSSam Estep Env.pushCallInternal(Call->getConstructor(), 635a3c248dbSserge-sans-paille llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 636eb91fd5cSSam Estep 637eb91fd5cSSam Estep return Env; 638eb91fd5cSSam Estep } 639eb91fd5cSSam Estep 640eb91fd5cSSam Estep void Environment::pushCallInternal(const FunctionDecl *FuncDecl, 641eb91fd5cSSam Estep ArrayRef<const Expr *> Args) { 64264413584SMartin Braenne // Canonicalize to the definition of the function. This ensures that we're 64364413584SMartin Braenne // putting arguments into the same `ParamVarDecl`s` that the callee will later 64464413584SMartin Braenne // be retrieving them from. 64564413584SMartin Braenne assert(FuncDecl->getDefinition() != nullptr); 64664413584SMartin Braenne FuncDecl = FuncDecl->getDefinition(); 64764413584SMartin Braenne 6482efc8f8dSSam Estep CallStack.push_back(FuncDecl); 6492cb51449SWei Yi Tee 65080d9ae9cSSamira Bazuzi initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl)); 6513ce03c42SYitzhak Mandelbaum 65201ccf7b3SYitzhak Mandelbaum const auto *ParamIt = FuncDecl->param_begin(); 653300fbf56SSam Estep 654300fbf56SSam Estep // FIXME: Parameters don't always map to arguments 1:1; examples include 655300fbf56SSam Estep // overloaded operators implemented as member functions, and parameter packs. 656eb91fd5cSSam Estep for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) { 6571f8ae9d7SWeverything assert(ParamIt != FuncDecl->param_end()); 658a6ddc684SSam Estep const VarDecl *Param = *ParamIt; 6596d768548SMartin Braenne setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); 660300fbf56SSam Estep } 66171f1932bSmartinboehme 66271f1932bSmartinboehme ResultObjectMap = std::make_shared<PrValueToResultObject>( 66371f1932bSmartinboehme buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), 66471f1932bSmartinboehme LocForRecordReturnVal)); 665bfbe1378SMartin Braenne } 666300fbf56SSam Estep 66764413584SMartin Braenne void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { 668330d5bcbSMartin Braenne // We ignore some entries of `CalleeEnv`: 669330d5bcbSMartin Braenne // - `DACtx` because is already the same in both 670330d5bcbSMartin Braenne // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or 671330d5bcbSMartin Braenne // `ThisPointeeLoc` because they don't apply to us. 672330d5bcbSMartin Braenne // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the 673330d5bcbSMartin Braenne // callee's local scope, so when popping that scope, we do not propagate 674330d5bcbSMartin Braenne // the maps. 675a6ddc684SSam Estep this->LocToVal = std::move(CalleeEnv.LocToVal); 676a6ddc684SSam Estep this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 67764413584SMartin Braenne 67864413584SMartin Braenne if (Call->isGLValue()) { 67964413584SMartin Braenne if (CalleeEnv.ReturnLoc != nullptr) 680b244b6aeSMartin Braenne setStorageLocation(*Call, *CalleeEnv.ReturnLoc); 68164413584SMartin Braenne } else if (!Call->getType()->isVoidType()) { 68264413584SMartin Braenne if (CalleeEnv.ReturnVal != nullptr) 683b244b6aeSMartin Braenne setValue(*Call, *CalleeEnv.ReturnVal); 68464413584SMartin Braenne } 68564413584SMartin Braenne } 68664413584SMartin Braenne 68764413584SMartin Braenne void Environment::popCall(const CXXConstructExpr *Call, 68864413584SMartin Braenne const Environment &CalleeEnv) { 68964413584SMartin Braenne // See also comment in `popCall(const CallExpr *, const Environment &)` above. 69064413584SMartin Braenne this->LocToVal = std::move(CalleeEnv.LocToVal); 69164413584SMartin Braenne this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 692a6ddc684SSam Estep } 693a6ddc684SSam Estep 6946b8800dfSStanislav Gatev bool Environment::equivalentTo(const Environment &Other, 6956b8800dfSStanislav Gatev Environment::ValueModel &Model) const { 696af7bc39bSStanislav Gatev assert(DACtx == Other.DACtx); 6976b8800dfSStanislav Gatev 69864413584SMartin Braenne if (ReturnVal != Other.ReturnVal) 69964413584SMartin Braenne return false; 70064413584SMartin Braenne 7010eaecbbcSSam Estep if (ReturnLoc != Other.ReturnLoc) 7020eaecbbcSSam Estep return false; 7030eaecbbcSSam Estep 70471f1932bSmartinboehme if (LocForRecordReturnVal != Other.LocForRecordReturnVal) 70571f1932bSmartinboehme return false; 70671f1932bSmartinboehme 7078611a77eSSam Estep if (ThisPointeeLoc != Other.ThisPointeeLoc) 7088611a77eSSam Estep return false; 7098611a77eSSam Estep 7106b8800dfSStanislav Gatev if (DeclToLoc != Other.DeclToLoc) 7116b8800dfSStanislav Gatev return false; 7126b8800dfSStanislav Gatev 7136b8800dfSStanislav Gatev if (ExprToLoc != Other.ExprToLoc) 7146b8800dfSStanislav Gatev return false; 7156b8800dfSStanislav Gatev 716330d5bcbSMartin Braenne if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model)) 7176b8800dfSStanislav Gatev return false; 718330d5bcbSMartin Braenne 719330d5bcbSMartin Braenne if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model)) 720330d5bcbSMartin Braenne return false; 7216b8800dfSStanislav Gatev 7226b8800dfSStanislav Gatev return true; 723af7bc39bSStanislav Gatev } 724af7bc39bSStanislav Gatev 725bbd259afSYitzhak Mandelbaum LatticeEffect Environment::widen(const Environment &PrevEnv, 72684dd12b2SYitzhak Mandelbaum Environment::ValueModel &Model) { 72784dd12b2SYitzhak Mandelbaum assert(DACtx == PrevEnv.DACtx); 72864413584SMartin Braenne assert(ReturnVal == PrevEnv.ReturnVal); 72984dd12b2SYitzhak Mandelbaum assert(ReturnLoc == PrevEnv.ReturnLoc); 73071f1932bSmartinboehme assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal); 73184dd12b2SYitzhak Mandelbaum assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); 73284dd12b2SYitzhak Mandelbaum assert(CallStack == PrevEnv.CallStack); 73371f1932bSmartinboehme assert(ResultObjectMap == PrevEnv.ResultObjectMap); 73480d9ae9cSSamira Bazuzi assert(InitialTargetFunc == PrevEnv.InitialTargetFunc); 73580d9ae9cSSamira Bazuzi assert(InitialTargetStmt == PrevEnv.InitialTargetStmt); 73684dd12b2SYitzhak Mandelbaum 737bbd259afSYitzhak Mandelbaum auto Effect = LatticeEffect::Unchanged; 73884dd12b2SYitzhak Mandelbaum 739d2e4aaf6SYitzhak Mandelbaum // By the API, `PrevEnv` is a previous version of the environment for the same 740d2e4aaf6SYitzhak Mandelbaum // block, so we have some guarantees about its shape. In particular, it will 741d2e4aaf6SYitzhak Mandelbaum // be the result of a join or widen operation on previous values for this 742330d5bcbSMartin Braenne // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that 743330d5bcbSMartin Braenne // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain 744330d5bcbSMartin Braenne // this property here, we don't need change their current values to widen. 74584dd12b2SYitzhak Mandelbaum assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size()); 746330d5bcbSMartin Braenne assert(ExprToVal.size() <= PrevEnv.ExprToVal.size()); 74784dd12b2SYitzhak Mandelbaum assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size()); 74884dd12b2SYitzhak Mandelbaum 749330d5bcbSMartin Braenne ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv, 750330d5bcbSMartin Braenne Model, Effect); 75184dd12b2SYitzhak Mandelbaum 752330d5bcbSMartin Braenne LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv, 753330d5bcbSMartin Braenne Model, Effect); 75484dd12b2SYitzhak Mandelbaum if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() || 75584dd12b2SYitzhak Mandelbaum ExprToLoc.size() != PrevEnv.ExprToLoc.size() || 756330d5bcbSMartin Braenne ExprToVal.size() != PrevEnv.ExprToVal.size() || 75744f98d01SMartin Braenne LocToVal.size() != PrevEnv.LocToVal.size()) 758bbd259afSYitzhak Mandelbaum Effect = LatticeEffect::Changed; 75984dd12b2SYitzhak Mandelbaum 76084dd12b2SYitzhak Mandelbaum return Effect; 76184dd12b2SYitzhak Mandelbaum } 76284dd12b2SYitzhak Mandelbaum 7636f22de67SSam McCall Environment Environment::join(const Environment &EnvA, const Environment &EnvB, 764d5aecf0cSmartinboehme Environment::ValueModel &Model, 765d5aecf0cSmartinboehme ExprJoinBehavior ExprBehavior) { 7666f22de67SSam McCall assert(EnvA.DACtx == EnvB.DACtx); 76771f1932bSmartinboehme assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal); 7686f22de67SSam McCall assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); 7696f22de67SSam McCall assert(EnvA.CallStack == EnvB.CallStack); 77071f1932bSmartinboehme assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap); 77180d9ae9cSSamira Bazuzi assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc); 77280d9ae9cSSamira Bazuzi assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt); 773af7bc39bSStanislav Gatev 7746f22de67SSam McCall Environment JoinedEnv(*EnvA.DACtx); 77537b4782eSYitzhak Mandelbaum 7766f22de67SSam McCall JoinedEnv.CallStack = EnvA.CallStack; 77771f1932bSmartinboehme JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap; 77871f1932bSmartinboehme JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal; 7796f22de67SSam McCall JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; 78080d9ae9cSSamira Bazuzi JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc; 78180d9ae9cSSamira Bazuzi JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt; 7820eaecbbcSSam Estep 78380d9ae9cSSamira Bazuzi const FunctionDecl *Func = EnvA.getCurrentFunc(); 78480d9ae9cSSamira Bazuzi if (!Func) { 78564413584SMartin Braenne JoinedEnv.ReturnVal = nullptr; 78664413584SMartin Braenne } else { 7879ba6961cSmartinboehme JoinedEnv.ReturnVal = 7889ba6961cSmartinboehme joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal, 7899ba6961cSmartinboehme EnvB, JoinedEnv, Model); 79064413584SMartin Braenne } 79164413584SMartin Braenne 7926f22de67SSam McCall if (EnvA.ReturnLoc == EnvB.ReturnLoc) 7936f22de67SSam McCall JoinedEnv.ReturnLoc = EnvA.ReturnLoc; 79464413584SMartin Braenne else 79564413584SMartin Braenne JoinedEnv.ReturnLoc = nullptr; 79664413584SMartin Braenne 797c4c59192Smartinboehme JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc); 798c95cb4deSStanislav Gatev 79984dd12b2SYitzhak Mandelbaum // FIXME: update join to detect backedges and simplify the flow condition 80084dd12b2SYitzhak Mandelbaum // accordingly. 801fc9821a8SSam McCall JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions( 802fc9821a8SSam McCall EnvA.FlowConditionToken, EnvB.FlowConditionToken); 80337b4782eSYitzhak Mandelbaum 804c4c59192Smartinboehme JoinedEnv.LocToVal = 805c4c59192Smartinboehme joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model); 806d3597ec0SStanislav Gatev 807d5aecf0cSmartinboehme if (ExprBehavior == KeepExprState) { 808d5aecf0cSmartinboehme JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal); 809d5aecf0cSmartinboehme JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc); 810d5aecf0cSmartinboehme } 811af7bc39bSStanislav Gatev 8121e010c5cSSam McCall return JoinedEnv; 813af7bc39bSStanislav Gatev } 814af7bc39bSStanislav Gatev 8159ba6961cSmartinboehme Value *Environment::joinValues(QualType Ty, Value *Val1, 8169ba6961cSmartinboehme const Environment &Env1, Value *Val2, 8179ba6961cSmartinboehme const Environment &Env2, Environment &JoinedEnv, 8189ba6961cSmartinboehme Environment::ValueModel &Model) { 8199ba6961cSmartinboehme if (Val1 == nullptr || Val2 == nullptr) 8209ba6961cSmartinboehme // We can't say anything about the joined value -- even if one of the values 8219ba6961cSmartinboehme // is non-null, we don't want to simply propagate it, because it would be 8229ba6961cSmartinboehme // too specific: Because the other value is null, that means we have no 8239ba6961cSmartinboehme // information at all about the value (i.e. the value is unconstrained). 8249ba6961cSmartinboehme return nullptr; 8259ba6961cSmartinboehme 8269ba6961cSmartinboehme if (areEquivalentValues(*Val1, *Val2)) 8279ba6961cSmartinboehme // Arbitrarily return one of the two values. 8289ba6961cSmartinboehme return Val1; 8299ba6961cSmartinboehme 8309ba6961cSmartinboehme return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model); 8319ba6961cSmartinboehme } 8329ba6961cSmartinboehme 833af7bc39bSStanislav Gatev StorageLocation &Environment::createStorageLocation(QualType Type) { 834817dd5e3SStanislav Gatev return DACtx->createStorageLocation(Type); 835af7bc39bSStanislav Gatev } 836af7bc39bSStanislav Gatev 83752d06963SStanislav Gatev StorageLocation &Environment::createStorageLocation(const ValueDecl &D) { 838af7bc39bSStanislav Gatev // Evaluated declarations are always assigned the same storage locations to 839af7bc39bSStanislav Gatev // ensure that the environment stabilizes across loop iterations. Storage 840af7bc39bSStanislav Gatev // locations for evaluated declarations are stored in the analysis context. 84112c7352fSWei Yi Tee return DACtx->getStableStorageLocation(D); 842af7bc39bSStanislav Gatev } 843af7bc39bSStanislav Gatev 844e7481f6eSStanislav Gatev StorageLocation &Environment::createStorageLocation(const Expr &E) { 845e7481f6eSStanislav Gatev // Evaluated expressions are always assigned the same storage locations to 846e7481f6eSStanislav Gatev // ensure that the environment stabilizes across loop iterations. Storage 847e7481f6eSStanislav Gatev // locations for evaluated expressions are stored in the analysis context. 84812c7352fSWei Yi Tee return DACtx->getStableStorageLocation(E); 849e7481f6eSStanislav Gatev } 850e7481f6eSStanislav Gatev 851af7bc39bSStanislav Gatev void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 8527eaa7b05SKazu Hirata assert(!DeclToLoc.contains(&D)); 85371f1932bSmartinboehme // The only kinds of declarations that may have a "variable" storage location 85471f1932bSmartinboehme // are declarations of reference type and `BindingDecl`. For all other 85571f1932bSmartinboehme // declaration, the storage location should be the stable storage location 85671f1932bSmartinboehme // returned by `createStorageLocation()`. 85771f1932bSmartinboehme assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) || 85871f1932bSmartinboehme &Loc == &createStorageLocation(D)); 859af7bc39bSStanislav Gatev DeclToLoc[&D] = &Loc; 860af7bc39bSStanislav Gatev } 861af7bc39bSStanislav Gatev 8629940fac7SMartin Braenne StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 863af7bc39bSStanislav Gatev auto It = DeclToLoc.find(&D); 864bfbe1378SMartin Braenne if (It == DeclToLoc.end()) 865bfbe1378SMartin Braenne return nullptr; 866bfbe1378SMartin Braenne 867bfbe1378SMartin Braenne StorageLocation *Loc = It->second; 868bfbe1378SMartin Braenne 869bfbe1378SMartin Braenne return Loc; 870e7481f6eSStanislav Gatev } 871e7481f6eSStanislav Gatev 87214b039c1Smartinboehme void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); } 873834cb919Smartinboehme 874b244b6aeSMartin Braenne void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 875080ee850SMartin Braenne // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason, 876080ee850SMartin Braenne // but we still want to be able to associate a `StorageLocation` with them, 877080ee850SMartin Braenne // so allow these as an exception. 878080ee850SMartin Braenne assert(E.isGLValue() || 879080ee850SMartin Braenne E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 880ca103434Smartinboehme const Expr &CanonE = ignoreCFGOmittedNodes(E); 881ca103434Smartinboehme assert(!ExprToLoc.contains(&CanonE)); 882ca103434Smartinboehme ExprToLoc[&CanonE] = &Loc; 883af7bc39bSStanislav Gatev } 884af7bc39bSStanislav Gatev 885b244b6aeSMartin Braenne StorageLocation *Environment::getStorageLocation(const Expr &E) const { 886b244b6aeSMartin Braenne // See comment in `setStorageLocation()`. 887080ee850SMartin Braenne assert(E.isGLValue() || 888080ee850SMartin Braenne E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 889ca103434Smartinboehme auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 890ca103434Smartinboehme return It == ExprToLoc.end() ? nullptr : &*It->second; 891ca103434Smartinboehme } 892ca103434Smartinboehme 8939ecdbe38SMartin Braenne RecordStorageLocation & 894ca103434Smartinboehme Environment::getResultObjectLocation(const Expr &RecordPRValue) const { 89544f98d01SMartin Braenne assert(RecordPRValue.getType()->isRecordType()); 89644f98d01SMartin Braenne assert(RecordPRValue.isPRValue()); 89744f98d01SMartin Braenne 89871f1932bSmartinboehme assert(ResultObjectMap != nullptr); 89971f1932bSmartinboehme RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue); 90071f1932bSmartinboehme assert(Loc != nullptr); 90171f1932bSmartinboehme // In release builds, use the "stable" storage location if the map lookup 90271f1932bSmartinboehme // failed. 90371f1932bSmartinboehme if (Loc == nullptr) 904ca103434Smartinboehme return cast<RecordStorageLocation>( 90544f98d01SMartin Braenne DACtx->getStableStorageLocation(RecordPRValue)); 90671f1932bSmartinboehme return *Loc; 90744f98d01SMartin Braenne } 90844f98d01SMartin Braenne 909b611376eSWei Yi Tee PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 910b611376eSWei Yi Tee return DACtx->getOrCreateNullPointerValue(PointeeType); 911b611376eSWei Yi Tee } 912b611376eSWei Yi Tee 91371f1932bSmartinboehme void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, 91471f1932bSmartinboehme QualType Type) { 9152d539db2Smartinboehme llvm::DenseSet<QualType> Visited; 9162d539db2Smartinboehme int CreatedValuesCount = 0; 91771f1932bSmartinboehme initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount); 9182d539db2Smartinboehme if (CreatedValuesCount > MaxCompositeValueSize) { 91971f1932bSmartinboehme llvm::errs() << "Attempting to initialize a huge value of type: " << Type 92071f1932bSmartinboehme << '\n'; 9212d539db2Smartinboehme } 9222d539db2Smartinboehme } 9232d539db2Smartinboehme 9247d941d6dSStanislav Gatev void Environment::setValue(const StorageLocation &Loc, Value &Val) { 925e8fce958Smartinboehme // Records should not be associated with values. 926e8fce958Smartinboehme assert(!isa<RecordStorageLocation>(Loc)); 9277d941d6dSStanislav Gatev LocToVal[&Loc] = &Val; 928f2123af1SMartin Braenne } 929f2123af1SMartin Braenne 930b244b6aeSMartin Braenne void Environment::setValue(const Expr &E, Value &Val) { 93123bfc271Smartinboehme const Expr &CanonE = ignoreCFGOmittedNodes(E); 93223bfc271Smartinboehme 93323bfc271Smartinboehme assert(CanonE.isPRValue()); 934e8fce958Smartinboehme // Records should not be associated with values. 935e8fce958Smartinboehme assert(!CanonE.getType()->isRecordType()); 93623bfc271Smartinboehme ExprToVal[&CanonE] = &Val; 937080ee850SMartin Braenne } 938080ee850SMartin Braenne 939af7bc39bSStanislav Gatev Value *Environment::getValue(const StorageLocation &Loc) const { 940e8fce958Smartinboehme // Records should not be associated with values. 941e8fce958Smartinboehme assert(!isa<RecordStorageLocation>(Loc)); 942583371beSKazu Hirata return LocToVal.lookup(&Loc); 943af7bc39bSStanislav Gatev } 944af7bc39bSStanislav Gatev 9450c852dc8SMartin Braenne Value *Environment::getValue(const ValueDecl &D) const { 9469940fac7SMartin Braenne auto *Loc = getStorageLocation(D); 947e7481f6eSStanislav Gatev if (Loc == nullptr) 948e7481f6eSStanislav Gatev return nullptr; 949e7481f6eSStanislav Gatev return getValue(*Loc); 950e7481f6eSStanislav Gatev } 951e7481f6eSStanislav Gatev 95217ba278fSMartin Braenne Value *Environment::getValue(const Expr &E) const { 953e8fce958Smartinboehme // Records should not be associated with values. 954e8fce958Smartinboehme assert(!E.getType()->isRecordType()); 955e8fce958Smartinboehme 956330d5bcbSMartin Braenne if (E.isPRValue()) { 957330d5bcbSMartin Braenne auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E)); 958330d5bcbSMartin Braenne return It == ExprToVal.end() ? nullptr : It->second; 959330d5bcbSMartin Braenne } 960330d5bcbSMartin Braenne 96117ba278fSMartin Braenne auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 96217ba278fSMartin Braenne if (It == ExprToLoc.end()) 963e7481f6eSStanislav Gatev return nullptr; 96417ba278fSMartin Braenne return getValue(*It->second); 965080ee850SMartin Braenne } 966080ee850SMartin Braenne 967782eced5SStanislav Gatev Value *Environment::createValue(QualType Type) { 968af7bc39bSStanislav Gatev llvm::DenseSet<QualType> Visited; 969208c25fcSYitzhak Mandelbaum int CreatedValuesCount = 0; 970208c25fcSYitzhak Mandelbaum Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 971208c25fcSYitzhak Mandelbaum CreatedValuesCount); 972208c25fcSYitzhak Mandelbaum if (CreatedValuesCount > MaxCompositeValueSize) { 973cfb81690SNathan James llvm::errs() << "Attempting to initialize a huge value of type: " << Type 974cfb81690SNathan James << '\n'; 975208c25fcSYitzhak Mandelbaum } 976208c25fcSYitzhak Mandelbaum return Val; 977af7bc39bSStanislav Gatev } 978af7bc39bSStanislav Gatev 979782eced5SStanislav Gatev Value *Environment::createValueUnlessSelfReferential( 980208c25fcSYitzhak Mandelbaum QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 981208c25fcSYitzhak Mandelbaum int &CreatedValuesCount) { 982af7bc39bSStanislav Gatev assert(!Type.isNull()); 9831b334a2aSMartin Braenne assert(!Type->isReferenceType()); 984e8fce958Smartinboehme assert(!Type->isRecordType()); 985af7bc39bSStanislav Gatev 986208c25fcSYitzhak Mandelbaum // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 987208c25fcSYitzhak Mandelbaum if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 988208c25fcSYitzhak Mandelbaum Depth > MaxCompositeValueDepth) 989208c25fcSYitzhak Mandelbaum return nullptr; 990208c25fcSYitzhak Mandelbaum 9911e571585SStanislav Gatev if (Type->isBooleanType()) { 9921e571585SStanislav Gatev CreatedValuesCount++; 9931e571585SStanislav Gatev return &makeAtomicBoolValue(); 9941e571585SStanislav Gatev } 9951e571585SStanislav Gatev 996af7bc39bSStanislav Gatev if (Type->isIntegerType()) { 99784dd12b2SYitzhak Mandelbaum // FIXME: consider instead `return nullptr`, given that we do nothing useful 99884dd12b2SYitzhak Mandelbaum // with integers, and so distinguishing them serves no purpose, but could 99984dd12b2SYitzhak Mandelbaum // prevent convergence. 1000208c25fcSYitzhak Mandelbaum CreatedValuesCount++; 1001fc9821a8SSam McCall return &arena().create<IntegerValue>(); 1002af7bc39bSStanislav Gatev } 1003af7bc39bSStanislav Gatev 10041b334a2aSMartin Braenne if (Type->isPointerType()) { 1005208c25fcSYitzhak Mandelbaum CreatedValuesCount++; 10063c8ead26SMartin Braenne QualType PointeeType = Type->getPointeeType(); 100744f98d01SMartin Braenne StorageLocation &PointeeLoc = 100844f98d01SMartin Braenne createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); 1009af7bc39bSStanislav Gatev 1010fc9821a8SSam McCall return &arena().create<PointerValue>(PointeeLoc); 1011af7bc39bSStanislav Gatev } 1012af7bc39bSStanislav Gatev 1013af7bc39bSStanislav Gatev return nullptr; 1014af7bc39bSStanislav Gatev } 1015af7bc39bSStanislav Gatev 101644f98d01SMartin Braenne StorageLocation & 101744f98d01SMartin Braenne Environment::createLocAndMaybeValue(QualType Ty, 101844f98d01SMartin Braenne llvm::DenseSet<QualType> &Visited, 101944f98d01SMartin Braenne int Depth, int &CreatedValuesCount) { 102044f98d01SMartin Braenne if (!Visited.insert(Ty.getCanonicalType()).second) 102144f98d01SMartin Braenne return createStorageLocation(Ty.getNonReferenceType()); 1022e8fce958Smartinboehme auto EraseVisited = llvm::make_scope_exit( 1023e8fce958Smartinboehme [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); }); 102444f98d01SMartin Braenne 102544f98d01SMartin Braenne Ty = Ty.getNonReferenceType(); 102644f98d01SMartin Braenne 1027e8fce958Smartinboehme if (Ty->isRecordType()) { 1028e8fce958Smartinboehme auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty)); 1029e8fce958Smartinboehme initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount); 1030e8fce958Smartinboehme return Loc; 1031e8fce958Smartinboehme } 103244f98d01SMartin Braenne 103344f98d01SMartin Braenne StorageLocation &Loc = createStorageLocation(Ty); 1034e8fce958Smartinboehme 1035e8fce958Smartinboehme if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth, 1036e8fce958Smartinboehme CreatedValuesCount)) 103744f98d01SMartin Braenne setValue(Loc, *Val); 1038e8fce958Smartinboehme 103944f98d01SMartin Braenne return Loc; 104044f98d01SMartin Braenne } 104144f98d01SMartin Braenne 1042270f2c55Smartinboehme void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, 104371f1932bSmartinboehme QualType Type, 1044270f2c55Smartinboehme llvm::DenseSet<QualType> &Visited, 1045270f2c55Smartinboehme int Depth, 1046270f2c55Smartinboehme int &CreatedValuesCount) { 1047270f2c55Smartinboehme auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) { 1048270f2c55Smartinboehme if (FieldType->isRecordType()) { 1049270f2c55Smartinboehme auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc); 105071f1932bSmartinboehme initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(), 105171f1932bSmartinboehme Visited, Depth + 1, CreatedValuesCount); 1052270f2c55Smartinboehme } else { 1053e8fce958Smartinboehme if (getValue(FieldLoc) != nullptr) 1054e8fce958Smartinboehme return; 1055270f2c55Smartinboehme if (!Visited.insert(FieldType.getCanonicalType()).second) 1056270f2c55Smartinboehme return; 1057270f2c55Smartinboehme if (Value *Val = createValueUnlessSelfReferential( 1058270f2c55Smartinboehme FieldType, Visited, Depth + 1, CreatedValuesCount)) 1059270f2c55Smartinboehme setValue(FieldLoc, *Val); 1060270f2c55Smartinboehme Visited.erase(FieldType.getCanonicalType()); 1061270f2c55Smartinboehme } 1062270f2c55Smartinboehme }; 1063270f2c55Smartinboehme 106471f1932bSmartinboehme for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { 1065270f2c55Smartinboehme assert(Field != nullptr); 1066270f2c55Smartinboehme QualType FieldType = Field->getType(); 1067270f2c55Smartinboehme 1068270f2c55Smartinboehme if (FieldType->isReferenceType()) { 1069270f2c55Smartinboehme Loc.setChild(*Field, 1070270f2c55Smartinboehme &createLocAndMaybeValue(FieldType, Visited, Depth + 1, 1071270f2c55Smartinboehme CreatedValuesCount)); 1072270f2c55Smartinboehme } else { 107371f1932bSmartinboehme StorageLocation *FieldLoc = Loc.getChild(*Field); 1074270f2c55Smartinboehme assert(FieldLoc != nullptr); 1075270f2c55Smartinboehme initField(FieldType, *FieldLoc); 1076270f2c55Smartinboehme } 1077270f2c55Smartinboehme } 107871f1932bSmartinboehme for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) { 1079270f2c55Smartinboehme // Synthetic fields cannot have reference type, so we don't need to deal 1080270f2c55Smartinboehme // with this case. 1081270f2c55Smartinboehme assert(!FieldType->isReferenceType()); 1082270f2c55Smartinboehme initField(FieldType, Loc.getSyntheticField(FieldName)); 1083270f2c55Smartinboehme } 1084270f2c55Smartinboehme } 1085270f2c55Smartinboehme 108652d06963SStanislav Gatev StorageLocation &Environment::createObjectInternal(const ValueDecl *D, 10876d768548SMartin Braenne QualType Ty, 10886d768548SMartin Braenne const Expr *InitExpr) { 10896d768548SMartin Braenne if (Ty->isReferenceType()) { 10906d768548SMartin Braenne // Although variables of reference type always need to be initialized, it 10916d768548SMartin Braenne // can happen that we can't see the initializer, so `InitExpr` may still 10926d768548SMartin Braenne // be null. 10936d768548SMartin Braenne if (InitExpr) { 1094b244b6aeSMartin Braenne if (auto *InitExprLoc = getStorageLocation(*InitExpr)) 10956d768548SMartin Braenne return *InitExprLoc; 10966d768548SMartin Braenne } 10976d768548SMartin Braenne 10986d768548SMartin Braenne // Even though we have an initializer, we might not get an 10996d768548SMartin Braenne // InitExprLoc, for example if the InitExpr is a CallExpr for which we 11006d768548SMartin Braenne // don't have a function body. In this case, we just invent a storage 11016d768548SMartin Braenne // location and value -- it's the best we can do. 11026d768548SMartin Braenne return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); 11036d768548SMartin Braenne } 11046d768548SMartin Braenne 110571f1932bSmartinboehme StorageLocation &Loc = 110671f1932bSmartinboehme D ? createStorageLocation(*D) : createStorageLocation(Ty); 110771f1932bSmartinboehme 110871f1932bSmartinboehme if (Ty->isRecordType()) { 110971f1932bSmartinboehme auto &RecordLoc = cast<RecordStorageLocation>(Loc); 111071f1932bSmartinboehme if (!InitExpr) 111171f1932bSmartinboehme initializeFieldsWithValues(RecordLoc); 111271f1932bSmartinboehme } else { 11136d768548SMartin Braenne Value *Val = nullptr; 111471f1932bSmartinboehme if (InitExpr) 11156d768548SMartin Braenne // In the (few) cases where an expression is intentionally 11166d768548SMartin Braenne // "uninterpreted", `InitExpr` is not associated with a value. There are 11176d768548SMartin Braenne // two ways to handle this situation: propagate the status, so that 11186d768548SMartin Braenne // uninterpreted initializers result in uninterpreted variables, or 11196d768548SMartin Braenne // provide a default value. We choose the latter so that later refinements 11206d768548SMartin Braenne // of the variable can be used for reasoning about the surrounding code. 11216d768548SMartin Braenne // For this reason, we let this case be handled by the `createValue()` 11226d768548SMartin Braenne // call below. 11236d768548SMartin Braenne // 11246d768548SMartin Braenne // FIXME. If and when we interpret all language cases, change this to 11256d768548SMartin Braenne // assert that `InitExpr` is interpreted, rather than supplying a 11266d768548SMartin Braenne // default value (assuming we don't update the environment API to return 11276d768548SMartin Braenne // references). 1128e95134b9SMartin Braenne Val = getValue(*InitExpr); 11296d768548SMartin Braenne if (!Val) 11306d768548SMartin Braenne Val = createValue(Ty); 11316d768548SMartin Braenne if (Val) 11326d768548SMartin Braenne setValue(Loc, *Val); 113371f1932bSmartinboehme } 11346d768548SMartin Braenne 11356d768548SMartin Braenne return Loc; 11366d768548SMartin Braenne } 11376d768548SMartin Braenne 1138d1f59544Smartinboehme void Environment::assume(const Formula &F) { 1139d1f59544Smartinboehme DACtx->addFlowConditionConstraint(FlowConditionToken, F); 1140fc9821a8SSam McCall } 1141ae60884dSStanislav Gatev 1142d1f59544Smartinboehme bool Environment::proves(const Formula &F) const { 1143d1f59544Smartinboehme return DACtx->flowConditionImplies(FlowConditionToken, F); 1144d1f59544Smartinboehme } 1145d1f59544Smartinboehme 1146d1f59544Smartinboehme bool Environment::allows(const Formula &F) const { 1147d1f59544Smartinboehme return DACtx->flowConditionAllows(FlowConditionToken, F); 1148fc9821a8SSam McCall } 1149ae60884dSStanislav Gatev 1150c441f65fSYitzhak Mandelbaum void Environment::dump(raw_ostream &OS) const { 1151c83ec847Smartinboehme llvm::DenseMap<const StorageLocation *, std::string> LocToName; 115271f1932bSmartinboehme if (LocForRecordReturnVal != nullptr) 115371f1932bSmartinboehme LocToName[LocForRecordReturnVal] = "(returned record)"; 1154c83ec847Smartinboehme if (ThisPointeeLoc != nullptr) 1155c83ec847Smartinboehme LocToName[ThisPointeeLoc] = "this"; 1156c441f65fSYitzhak Mandelbaum 1157c83ec847Smartinboehme OS << "DeclToLoc:\n"; 1158c83ec847Smartinboehme for (auto [D, L] : DeclToLoc) { 1159c83ec847Smartinboehme auto Iter = LocToName.insert({L, D->getNameAsString()}).first; 1160c83ec847Smartinboehme OS << " [" << Iter->second << ", " << L << "]\n"; 1161c83ec847Smartinboehme } 1162c441f65fSYitzhak Mandelbaum OS << "ExprToLoc:\n"; 1163c441f65fSYitzhak Mandelbaum for (auto [E, L] : ExprToLoc) 1164c441f65fSYitzhak Mandelbaum OS << " [" << E << ", " << L << "]\n"; 1165c441f65fSYitzhak Mandelbaum 1166330d5bcbSMartin Braenne OS << "ExprToVal:\n"; 1167330d5bcbSMartin Braenne for (auto [E, V] : ExprToVal) 1168266c12a1SMartin Braenne OS << " [" << E << ", " << V << ": " << *V << "]\n"; 1169330d5bcbSMartin Braenne 1170c441f65fSYitzhak Mandelbaum OS << "LocToVal:\n"; 1171c441f65fSYitzhak Mandelbaum for (auto [L, V] : LocToVal) { 1172c83ec847Smartinboehme OS << " [" << L; 1173c83ec847Smartinboehme if (auto Iter = LocToName.find(L); Iter != LocToName.end()) 1174c83ec847Smartinboehme OS << " (" << Iter->second << ")"; 1175c83ec847Smartinboehme OS << ", " << V << ": " << *V << "]\n"; 1176c83ec847Smartinboehme } 1177c83ec847Smartinboehme 1178c83ec847Smartinboehme if (const FunctionDecl *Func = getCurrentFunc()) { 1179c83ec847Smartinboehme if (Func->getReturnType()->isReferenceType()) { 1180c83ec847Smartinboehme OS << "ReturnLoc: " << ReturnLoc; 1181c83ec847Smartinboehme if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end()) 1182c83ec847Smartinboehme OS << " (" << Iter->second << ")"; 1183c83ec847Smartinboehme OS << "\n"; 118471f1932bSmartinboehme } else if (Func->getReturnType()->isRecordType() || 118571f1932bSmartinboehme isa<CXXConstructorDecl>(Func)) { 118671f1932bSmartinboehme OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n"; 1187c83ec847Smartinboehme } else if (!Func->getReturnType()->isVoidType()) { 1188c83ec847Smartinboehme if (ReturnVal == nullptr) 1189c83ec847Smartinboehme OS << "ReturnVal: nullptr\n"; 1190c83ec847Smartinboehme else 1191c83ec847Smartinboehme OS << "ReturnVal: " << *ReturnVal << "\n"; 1192c83ec847Smartinboehme } 1193c83ec847Smartinboehme 1194c83ec847Smartinboehme if (isa<CXXMethodDecl>(Func)) { 1195c83ec847Smartinboehme OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n"; 1196c83ec847Smartinboehme } 1197c441f65fSYitzhak Mandelbaum } 1198c441f65fSYitzhak Mandelbaum 11997c636728Smartinboehme OS << "\n"; 1200fc9821a8SSam McCall DACtx->dumpFlowCondition(FlowConditionToken, OS); 1201b5414b56SDmitri Gribenko } 1202b5414b56SDmitri Gribenko 120314122106Smartinboehme void Environment::dump() const { dump(llvm::dbgs()); } 1204c441f65fSYitzhak Mandelbaum 120571f1932bSmartinboehme Environment::PrValueToResultObject Environment::buildResultObjectMap( 120671f1932bSmartinboehme DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl, 120771f1932bSmartinboehme RecordStorageLocation *ThisPointeeLoc, 120871f1932bSmartinboehme RecordStorageLocation *LocForRecordReturnVal) { 120971f1932bSmartinboehme assert(FuncDecl->doesThisDeclarationHaveABody()); 121071f1932bSmartinboehme 121180d9ae9cSSamira Bazuzi PrValueToResultObject Map = buildResultObjectMap( 121280d9ae9cSSamira Bazuzi DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal); 121371f1932bSmartinboehme 121471f1932bSmartinboehme ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); 121571f1932bSmartinboehme if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) 1216dde802b1SSirraide Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc); 121771f1932bSmartinboehme 121871f1932bSmartinboehme return Map; 121971f1932bSmartinboehme } 122071f1932bSmartinboehme 122180d9ae9cSSamira Bazuzi Environment::PrValueToResultObject Environment::buildResultObjectMap( 122280d9ae9cSSamira Bazuzi DataflowAnalysisContext *DACtx, Stmt *S, 122380d9ae9cSSamira Bazuzi RecordStorageLocation *ThisPointeeLoc, 122480d9ae9cSSamira Bazuzi RecordStorageLocation *LocForRecordReturnVal) { 122580d9ae9cSSamira Bazuzi PrValueToResultObject Map; 122680d9ae9cSSamira Bazuzi ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); 122780d9ae9cSSamira Bazuzi Visitor.TraverseStmt(S); 122880d9ae9cSSamira Bazuzi return Map; 122980d9ae9cSSamira Bazuzi } 123080d9ae9cSSamira Bazuzi 12319ecdbe38SMartin Braenne RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 123248bc7150SMartin Braenne const Environment &Env) { 123348bc7150SMartin Braenne Expr *ImplicitObject = MCE.getImplicitObjectArgument(); 123448bc7150SMartin Braenne if (ImplicitObject == nullptr) 123548bc7150SMartin Braenne return nullptr; 123648bc7150SMartin Braenne if (ImplicitObject->getType()->isPointerType()) { 12372ee396b0Smartinboehme if (auto *Val = Env.get<PointerValue>(*ImplicitObject)) 12389ecdbe38SMartin Braenne return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 123948bc7150SMartin Braenne return nullptr; 124048bc7150SMartin Braenne } 12419ecdbe38SMartin Braenne return cast_or_null<RecordStorageLocation>( 1242b244b6aeSMartin Braenne Env.getStorageLocation(*ImplicitObject)); 124348bc7150SMartin Braenne } 124448bc7150SMartin Braenne 12459ecdbe38SMartin Braenne RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 124648bc7150SMartin Braenne const Environment &Env) { 124748bc7150SMartin Braenne Expr *Base = ME.getBase(); 124848bc7150SMartin Braenne if (Base == nullptr) 124948bc7150SMartin Braenne return nullptr; 125048bc7150SMartin Braenne if (ME.isArrow()) { 12512ee396b0Smartinboehme if (auto *Val = Env.get<PointerValue>(*Base)) 12529ecdbe38SMartin Braenne return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 125348bc7150SMartin Braenne return nullptr; 125448bc7150SMartin Braenne } 12552ee396b0Smartinboehme return Env.get<RecordStorageLocation>(*Base); 125648bc7150SMartin Braenne } 125748bc7150SMartin Braenne 1258af7bc39bSStanislav Gatev } // namespace dataflow 1259af7bc39bSStanislav Gatev } // namespace clang 1260