104eeddc0SDimitry Andric //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// 204eeddc0SDimitry Andric // 304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 604eeddc0SDimitry Andric // 704eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 804eeddc0SDimitry Andric // 904eeddc0SDimitry Andric // This file defines an Environment class that is used by dataflow analyses 1004eeddc0SDimitry Andric // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 1104eeddc0SDimitry Andric // program at given program points. 1204eeddc0SDimitry Andric // 1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1404eeddc0SDimitry Andric 1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 1604eeddc0SDimitry Andric #include "clang/AST/Decl.h" 1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h" 18*0fca6ea1SDimitry Andric #include "clang/AST/ExprCXX.h" 19*0fca6ea1SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 20*0fca6ea1SDimitry Andric #include "clang/AST/Stmt.h" 2104eeddc0SDimitry Andric #include "clang/AST/Type.h" 22*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h" 23*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 2404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2604eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 2704eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 2806c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h" 29*0fca6ea1SDimitry Andric #include "llvm/ADT/PointerUnion.h" 30bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 31*0fca6ea1SDimitry Andric #include "llvm/ADT/ScopeExit.h" 3204eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 33*0fca6ea1SDimitry Andric #include <algorithm> 3481ad6265SDimitry Andric #include <cassert> 35*0fca6ea1SDimitry Andric #include <memory> 3604eeddc0SDimitry Andric #include <utility> 3704eeddc0SDimitry Andric 38*0fca6ea1SDimitry Andric #define DEBUG_TYPE "dataflow" 39*0fca6ea1SDimitry Andric 4004eeddc0SDimitry Andric namespace clang { 4104eeddc0SDimitry Andric namespace dataflow { 4204eeddc0SDimitry Andric 4381ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 4481ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 4581ad6265SDimitry Andric // analysis. 4681ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 4781ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 4881ad6265SDimitry Andric 4904eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 505f757f3fSDimitry Andric static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc( 515f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1, 525f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) { 535f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> Result; 545f757f3fSDimitry Andric for (auto &Entry : DeclToLoc1) { 555f757f3fSDimitry Andric auto It = DeclToLoc2.find(Entry.first); 565f757f3fSDimitry Andric if (It != DeclToLoc2.end() && Entry.second == It->second) 5704eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 5804eeddc0SDimitry Andric } 5904eeddc0SDimitry Andric return Result; 6004eeddc0SDimitry Andric } 6104eeddc0SDimitry Andric 62*0fca6ea1SDimitry Andric // Performs a join on either `ExprToLoc` or `ExprToVal`. 63*0fca6ea1SDimitry Andric // The maps must be consistent in the sense that any entries for the same 64*0fca6ea1SDimitry Andric // expression must map to the same location / value. This is the case if we are 65*0fca6ea1SDimitry Andric // performing a join for control flow within a full-expression (which is the 66*0fca6ea1SDimitry Andric // only case when this function should be used). 67*0fca6ea1SDimitry Andric template <typename MapT> MapT joinExprMaps(const MapT &Map1, const MapT &Map2) { 68*0fca6ea1SDimitry Andric MapT Result = Map1; 69*0fca6ea1SDimitry Andric 70*0fca6ea1SDimitry Andric for (const auto &Entry : Map2) { 71*0fca6ea1SDimitry Andric [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry); 72*0fca6ea1SDimitry Andric // If there was an existing entry, its value should be the same as for the 73*0fca6ea1SDimitry Andric // entry we were trying to insert. 74*0fca6ea1SDimitry Andric assert(It->second == Entry.second); 75*0fca6ea1SDimitry Andric } 76*0fca6ea1SDimitry Andric 77*0fca6ea1SDimitry Andric return Result; 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric 805f757f3fSDimitry Andric // Whether to consider equivalent two values with an unknown relation. 815f757f3fSDimitry Andric // 825f757f3fSDimitry Andric // FIXME: this function is a hack enabling unsoundness to support 835f757f3fSDimitry Andric // convergence. Once we have widening support for the reference/pointer and 845f757f3fSDimitry Andric // struct built-in models, this should be unconditionally `false` (and inlined 855f757f3fSDimitry Andric // as such at its call sites). 865f757f3fSDimitry Andric static bool equateUnknownValues(Value::Kind K) { 875f757f3fSDimitry Andric switch (K) { 885f757f3fSDimitry Andric case Value::Kind::Integer: 895f757f3fSDimitry Andric case Value::Kind::Pointer: 905f757f3fSDimitry Andric return true; 915f757f3fSDimitry Andric default: 925f757f3fSDimitry Andric return false; 935f757f3fSDimitry Andric } 945f757f3fSDimitry Andric } 955f757f3fSDimitry Andric 96bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1, 97bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 9881ad6265SDimitry Andric const Environment &Env2, 9981ad6265SDimitry Andric Environment::ValueModel &Model) { 100bdd1243dSDimitry Andric // Note: Potentially costly, but, for booleans, we could check whether both 101bdd1243dSDimitry Andric // can be proven equivalent in their respective environments. 102bdd1243dSDimitry Andric 103bdd1243dSDimitry Andric // FIXME: move the reference/pointers logic from `areEquivalentValues` to here 104bdd1243dSDimitry Andric // and implement separate, join/widen specific handling for 105bdd1243dSDimitry Andric // reference/pointers. 106bdd1243dSDimitry Andric switch (Model.compare(Type, Val1, Env1, Val2, Env2)) { 107bdd1243dSDimitry Andric case ComparisonResult::Same: 108bdd1243dSDimitry Andric return true; 109bdd1243dSDimitry Andric case ComparisonResult::Different: 110bdd1243dSDimitry Andric return false; 111bdd1243dSDimitry Andric case ComparisonResult::Unknown: 1125f757f3fSDimitry Andric return equateUnknownValues(Val1.getKind()); 113bdd1243dSDimitry Andric } 114bdd1243dSDimitry Andric llvm_unreachable("All cases covered in switch"); 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric 117*0fca6ea1SDimitry Andric /// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`, 118*0fca6ea1SDimitry Andric /// respectively, of the same type `Type`. Joining generally produces a single 11981ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 12081ad6265SDimitry Andric /// meaning depends on `Model`. 121*0fca6ea1SDimitry Andric static Value *joinDistinctValues(QualType Type, Value &Val1, 122bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 12381ad6265SDimitry Andric const Environment &Env2, 124*0fca6ea1SDimitry Andric Environment &JoinedEnv, 12581ad6265SDimitry Andric Environment::ValueModel &Model) { 12681ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 12781ad6265SDimitry Andric // in the respective path conditions. 128bdd1243dSDimitry Andric if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) { 129bdd1243dSDimitry Andric // FIXME: Checking both values should be unnecessary, since they should have 130bdd1243dSDimitry Andric // a consistent shape. However, right now we can end up with BoolValue's in 131bdd1243dSDimitry Andric // integer-typed variables due to our incorrect handling of 132bdd1243dSDimitry Andric // boolean-to-integer casts (we just propagate the BoolValue to the result 133bdd1243dSDimitry Andric // of the cast). So, a join can encounter an integer in one branch but a 134bdd1243dSDimitry Andric // bool in the other. 135bdd1243dSDimitry Andric // For example: 136bdd1243dSDimitry Andric // ``` 137bdd1243dSDimitry Andric // std::optional<bool> o; 138bdd1243dSDimitry Andric // int x; 139bdd1243dSDimitry Andric // if (o.has_value()) 140bdd1243dSDimitry Andric // x = o.value(); 141bdd1243dSDimitry Andric // ``` 14206c3fb27SDimitry Andric auto &Expr1 = cast<BoolValue>(Val1).formula(); 14306c3fb27SDimitry Andric auto &Expr2 = cast<BoolValue>(Val2).formula(); 144*0fca6ea1SDimitry Andric auto &A = JoinedEnv.arena(); 145*0fca6ea1SDimitry Andric auto &JoinedVal = A.makeAtomRef(A.makeAtom()); 146*0fca6ea1SDimitry Andric JoinedEnv.assume( 14706c3fb27SDimitry Andric A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()), 148*0fca6ea1SDimitry Andric A.makeEquals(JoinedVal, Expr1)), 14906c3fb27SDimitry Andric A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()), 150*0fca6ea1SDimitry Andric A.makeEquals(JoinedVal, Expr2)))); 151*0fca6ea1SDimitry Andric return &A.makeBoolValue(JoinedVal); 15206c3fb27SDimitry Andric } 15306c3fb27SDimitry Andric 154*0fca6ea1SDimitry Andric Value *JoinedVal = JoinedEnv.createValue(Type); 155*0fca6ea1SDimitry Andric if (JoinedVal) 156*0fca6ea1SDimitry Andric Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv); 15706c3fb27SDimitry Andric 158*0fca6ea1SDimitry Andric return JoinedVal; 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric 161*0fca6ea1SDimitry Andric static WidenResult widenDistinctValues(QualType Type, Value &Prev, 162*0fca6ea1SDimitry Andric const Environment &PrevEnv, 163*0fca6ea1SDimitry Andric Value &Current, Environment &CurrentEnv, 164bdd1243dSDimitry Andric Environment::ValueModel &Model) { 165bdd1243dSDimitry Andric // Boolean-model widening. 166*0fca6ea1SDimitry Andric if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) { 167*0fca6ea1SDimitry Andric // FIXME: Checking both values should be unnecessary, but we can currently 168*0fca6ea1SDimitry Andric // end up with `BoolValue`s in integer-typed variables. See comment in 169*0fca6ea1SDimitry Andric // `joinDistinctValues()` for details. 170*0fca6ea1SDimitry Andric auto &PrevBool = cast<BoolValue>(Prev); 171*0fca6ea1SDimitry Andric auto &CurBool = cast<BoolValue>(Current); 172*0fca6ea1SDimitry Andric 173bdd1243dSDimitry Andric if (isa<TopBoolValue>(Prev)) 174*0fca6ea1SDimitry Andric // Safe to return `Prev` here, because Top is never dependent on the 175*0fca6ea1SDimitry Andric // environment. 176*0fca6ea1SDimitry Andric return {&Prev, LatticeEffect::Unchanged}; 1775f757f3fSDimitry Andric 1785f757f3fSDimitry Andric // We may need to widen to Top, but before we do so, check whether both 1795f757f3fSDimitry Andric // values are implied to be either true or false in the current environment. 1805f757f3fSDimitry Andric // In that case, we can simply return a literal instead. 181*0fca6ea1SDimitry Andric bool TruePrev = PrevEnv.proves(PrevBool.formula()); 1825f757f3fSDimitry Andric bool TrueCur = CurrentEnv.proves(CurBool.formula()); 1835f757f3fSDimitry Andric if (TruePrev && TrueCur) 184*0fca6ea1SDimitry Andric return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged}; 1855f757f3fSDimitry Andric if (!TruePrev && !TrueCur && 186*0fca6ea1SDimitry Andric PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) && 1875f757f3fSDimitry Andric CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) 188*0fca6ea1SDimitry Andric return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged}; 1895f757f3fSDimitry Andric 190*0fca6ea1SDimitry Andric return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed}; 191bdd1243dSDimitry Andric } 19281ad6265SDimitry Andric 193bdd1243dSDimitry Andric // FIXME: Add other built-in model widening. 194bdd1243dSDimitry Andric 195bdd1243dSDimitry Andric // Custom-model widening. 196*0fca6ea1SDimitry Andric if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) 197*0fca6ea1SDimitry Andric return *Result; 198bdd1243dSDimitry Andric 199*0fca6ea1SDimitry Andric return {&Current, equateUnknownValues(Prev.getKind()) 200*0fca6ea1SDimitry Andric ? LatticeEffect::Unchanged 201*0fca6ea1SDimitry Andric : LatticeEffect::Changed}; 2025f757f3fSDimitry Andric } 2035f757f3fSDimitry Andric 2045f757f3fSDimitry Andric // Returns whether the values in `Map1` and `Map2` compare equal for those 2055f757f3fSDimitry Andric // keys that `Map1` and `Map2` have in common. 2065f757f3fSDimitry Andric template <typename Key> 2075f757f3fSDimitry Andric bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1, 2085f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &Map2, 2095f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 2105f757f3fSDimitry Andric Environment::ValueModel &Model) { 2115f757f3fSDimitry Andric for (auto &Entry : Map1) { 2125f757f3fSDimitry Andric Key K = Entry.first; 2135f757f3fSDimitry Andric assert(K != nullptr); 2145f757f3fSDimitry Andric 2155f757f3fSDimitry Andric Value *Val = Entry.second; 2165f757f3fSDimitry Andric assert(Val != nullptr); 2175f757f3fSDimitry Andric 2185f757f3fSDimitry Andric auto It = Map2.find(K); 2195f757f3fSDimitry Andric if (It == Map2.end()) 2205f757f3fSDimitry Andric continue; 2215f757f3fSDimitry Andric assert(It->second != nullptr); 2225f757f3fSDimitry Andric 2235f757f3fSDimitry Andric if (!areEquivalentValues(*Val, *It->second) && 2245f757f3fSDimitry Andric !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2, 2255f757f3fSDimitry Andric Model)) 2265f757f3fSDimitry Andric return false; 2275f757f3fSDimitry Andric } 2285f757f3fSDimitry Andric 2295f757f3fSDimitry Andric return true; 2305f757f3fSDimitry Andric } 2315f757f3fSDimitry Andric 2325f757f3fSDimitry Andric // Perform a join on two `LocToVal` maps. 2335f757f3fSDimitry Andric static llvm::MapVector<const StorageLocation *, Value *> 2345f757f3fSDimitry Andric joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal, 2355f757f3fSDimitry Andric const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2, 2365f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 2375f757f3fSDimitry Andric Environment &JoinedEnv, Environment::ValueModel &Model) { 2385f757f3fSDimitry Andric llvm::MapVector<const StorageLocation *, Value *> Result; 2395f757f3fSDimitry Andric for (auto &Entry : LocToVal) { 2405f757f3fSDimitry Andric const StorageLocation *Loc = Entry.first; 2415f757f3fSDimitry Andric assert(Loc != nullptr); 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric Value *Val = Entry.second; 2445f757f3fSDimitry Andric assert(Val != nullptr); 2455f757f3fSDimitry Andric 2465f757f3fSDimitry Andric auto It = LocToVal2.find(Loc); 2475f757f3fSDimitry Andric if (It == LocToVal2.end()) 2485f757f3fSDimitry Andric continue; 2495f757f3fSDimitry Andric assert(It->second != nullptr); 2505f757f3fSDimitry Andric 251*0fca6ea1SDimitry Andric if (Value *JoinedVal = Environment::joinValues( 252*0fca6ea1SDimitry Andric Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) { 253*0fca6ea1SDimitry Andric Result.insert({Loc, JoinedVal}); 2545f757f3fSDimitry Andric } 2555f757f3fSDimitry Andric } 2565f757f3fSDimitry Andric 2575f757f3fSDimitry Andric return Result; 2585f757f3fSDimitry Andric } 2595f757f3fSDimitry Andric 2605f757f3fSDimitry Andric // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either 2615f757f3fSDimitry Andric // `const StorageLocation *` or `const Expr *`. 2625f757f3fSDimitry Andric template <typename Key> 2635f757f3fSDimitry Andric llvm::MapVector<Key, Value *> 2645f757f3fSDimitry Andric widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, 2655f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &PrevMap, 2665f757f3fSDimitry Andric Environment &CurEnv, const Environment &PrevEnv, 267*0fca6ea1SDimitry Andric Environment::ValueModel &Model, LatticeEffect &Effect) { 2685f757f3fSDimitry Andric llvm::MapVector<Key, Value *> WidenedMap; 2695f757f3fSDimitry Andric for (auto &Entry : CurMap) { 2705f757f3fSDimitry Andric Key K = Entry.first; 2715f757f3fSDimitry Andric assert(K != nullptr); 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric Value *Val = Entry.second; 2745f757f3fSDimitry Andric assert(Val != nullptr); 2755f757f3fSDimitry Andric 2765f757f3fSDimitry Andric auto PrevIt = PrevMap.find(K); 2775f757f3fSDimitry Andric if (PrevIt == PrevMap.end()) 2785f757f3fSDimitry Andric continue; 2795f757f3fSDimitry Andric assert(PrevIt->second != nullptr); 2805f757f3fSDimitry Andric 2815f757f3fSDimitry Andric if (areEquivalentValues(*Val, *PrevIt->second)) { 2825f757f3fSDimitry Andric WidenedMap.insert({K, Val}); 2835f757f3fSDimitry Andric continue; 2845f757f3fSDimitry Andric } 2855f757f3fSDimitry Andric 286*0fca6ea1SDimitry Andric auto [WidenedVal, ValEffect] = widenDistinctValues( 287*0fca6ea1SDimitry Andric K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model); 288*0fca6ea1SDimitry Andric WidenedMap.insert({K, WidenedVal}); 289*0fca6ea1SDimitry Andric if (ValEffect == LatticeEffect::Changed) 290*0fca6ea1SDimitry Andric Effect = LatticeEffect::Changed; 2915f757f3fSDimitry Andric } 2925f757f3fSDimitry Andric 2935f757f3fSDimitry Andric return WidenedMap; 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 296*0fca6ea1SDimitry Andric namespace { 297*0fca6ea1SDimitry Andric 298*0fca6ea1SDimitry Andric // Visitor that builds a map from record prvalues to result objects. 299*0fca6ea1SDimitry Andric // For each result object that it encounters, it propagates the storage location 300*0fca6ea1SDimitry Andric // of the result object to all record prvalues that can initialize it. 301*0fca6ea1SDimitry Andric class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> { 302*0fca6ea1SDimitry Andric public: 303*0fca6ea1SDimitry Andric // `ResultObjectMap` will be filled with a map from record prvalues to result 304*0fca6ea1SDimitry Andric // object. If this visitor will traverse a function that returns a record by 305*0fca6ea1SDimitry Andric // value, `LocForRecordReturnVal` is the location to which this record should 306*0fca6ea1SDimitry Andric // be written; otherwise, it is null. 307*0fca6ea1SDimitry Andric explicit ResultObjectVisitor( 308*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap, 309*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal, 310*0fca6ea1SDimitry Andric DataflowAnalysisContext &DACtx) 311*0fca6ea1SDimitry Andric : ResultObjectMap(ResultObjectMap), 312*0fca6ea1SDimitry Andric LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {} 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric // Traverse all member and base initializers of `Ctor`. This function is not 315*0fca6ea1SDimitry Andric // called by `RecursiveASTVisitor`; it should be called manually if we are 316*0fca6ea1SDimitry Andric // analyzing a constructor. `ThisPointeeLoc` is the storage location that 317*0fca6ea1SDimitry Andric // `this` points to. 318*0fca6ea1SDimitry Andric void TraverseConstructorInits(const CXXConstructorDecl *Ctor, 319*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc) { 320*0fca6ea1SDimitry Andric assert(ThisPointeeLoc != nullptr); 321*0fca6ea1SDimitry Andric for (const CXXCtorInitializer *Init : Ctor->inits()) { 322*0fca6ea1SDimitry Andric Expr *InitExpr = Init->getInit(); 323*0fca6ea1SDimitry Andric if (FieldDecl *Field = Init->getMember(); 324*0fca6ea1SDimitry Andric Field != nullptr && Field->getType()->isRecordType()) { 325*0fca6ea1SDimitry Andric PropagateResultObject(InitExpr, cast<RecordStorageLocation>( 326*0fca6ea1SDimitry Andric ThisPointeeLoc->getChild(*Field))); 327*0fca6ea1SDimitry Andric } else if (Init->getBaseClass()) { 328*0fca6ea1SDimitry Andric PropagateResultObject(InitExpr, ThisPointeeLoc); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 331*0fca6ea1SDimitry Andric // Ensure that any result objects within `InitExpr` (e.g. temporaries) 332*0fca6ea1SDimitry Andric // are also propagated to the prvalues that initialize them. 333*0fca6ea1SDimitry Andric TraverseStmt(InitExpr); 33406c3fb27SDimitry Andric 335*0fca6ea1SDimitry Andric // If this is a `CXXDefaultInitExpr`, also propagate any result objects 336*0fca6ea1SDimitry Andric // within the default expression. 337*0fca6ea1SDimitry Andric if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr)) 338*0fca6ea1SDimitry Andric TraverseStmt(DefaultInit->getExpr()); 339bdd1243dSDimitry Andric } 340bdd1243dSDimitry Andric } 341bdd1243dSDimitry Andric 342*0fca6ea1SDimitry Andric bool VisitVarDecl(VarDecl *VD) { 343*0fca6ea1SDimitry Andric if (VD->getType()->isRecordType() && VD->hasInit()) 344*0fca6ea1SDimitry Andric PropagateResultObject( 345*0fca6ea1SDimitry Andric VD->getInit(), 346*0fca6ea1SDimitry Andric &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD))); 347*0fca6ea1SDimitry Andric return true; 3485f757f3fSDimitry Andric } 3495f757f3fSDimitry Andric 350*0fca6ea1SDimitry Andric bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) { 351*0fca6ea1SDimitry Andric if (MTE->getType()->isRecordType()) 352*0fca6ea1SDimitry Andric PropagateResultObject( 353*0fca6ea1SDimitry Andric MTE->getSubExpr(), 354*0fca6ea1SDimitry Andric &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE))); 355*0fca6ea1SDimitry Andric return true; 356*0fca6ea1SDimitry Andric } 357*0fca6ea1SDimitry Andric 358*0fca6ea1SDimitry Andric bool VisitReturnStmt(ReturnStmt *Return) { 359*0fca6ea1SDimitry Andric Expr *RetValue = Return->getRetValue(); 360*0fca6ea1SDimitry Andric if (RetValue != nullptr && RetValue->getType()->isRecordType() && 361*0fca6ea1SDimitry Andric RetValue->isPRValue()) 362*0fca6ea1SDimitry Andric PropagateResultObject(RetValue, LocForRecordReturnVal); 363*0fca6ea1SDimitry Andric return true; 364*0fca6ea1SDimitry Andric } 365*0fca6ea1SDimitry Andric 366*0fca6ea1SDimitry Andric bool VisitExpr(Expr *E) { 367*0fca6ea1SDimitry Andric // Clang's AST can have record-type prvalues without a result object -- for 368*0fca6ea1SDimitry Andric // example as full-expressions contained in a compound statement or as 369*0fca6ea1SDimitry Andric // arguments of call expressions. We notice this if we get here and a 370*0fca6ea1SDimitry Andric // storage location has not yet been associated with `E`. In this case, 371*0fca6ea1SDimitry Andric // treat this as if it was a `MaterializeTemporaryExpr`. 372*0fca6ea1SDimitry Andric if (E->isPRValue() && E->getType()->isRecordType() && 373*0fca6ea1SDimitry Andric !ResultObjectMap.contains(E)) 374*0fca6ea1SDimitry Andric PropagateResultObject( 375*0fca6ea1SDimitry Andric E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E))); 376*0fca6ea1SDimitry Andric return true; 377*0fca6ea1SDimitry Andric } 378*0fca6ea1SDimitry Andric 379*0fca6ea1SDimitry Andric void 380*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList, 381*0fca6ea1SDimitry Andric RecordStorageLocation *Loc) { 382*0fca6ea1SDimitry Andric for (auto [Base, Init] : InitList.base_inits()) { 383*0fca6ea1SDimitry Andric assert(Base->getType().getCanonicalType() == 384*0fca6ea1SDimitry Andric Init->getType().getCanonicalType()); 385*0fca6ea1SDimitry Andric 386*0fca6ea1SDimitry Andric // Storage location for the base class is the same as that of the 387*0fca6ea1SDimitry Andric // derived class because we "flatten" the object hierarchy and put all 388*0fca6ea1SDimitry Andric // fields in `RecordStorageLocation` of the derived class. 389*0fca6ea1SDimitry Andric PropagateResultObject(Init, Loc); 390*0fca6ea1SDimitry Andric } 391*0fca6ea1SDimitry Andric 392*0fca6ea1SDimitry Andric for (auto [Field, Init] : InitList.field_inits()) { 393*0fca6ea1SDimitry Andric // Fields of non-record type are handled in 394*0fca6ea1SDimitry Andric // `TransferVisitor::VisitInitListExpr()`. 395*0fca6ea1SDimitry Andric if (Field->getType()->isRecordType()) 396*0fca6ea1SDimitry Andric PropagateResultObject( 397*0fca6ea1SDimitry Andric Init, cast<RecordStorageLocation>(Loc->getChild(*Field))); 398*0fca6ea1SDimitry Andric } 399*0fca6ea1SDimitry Andric } 400*0fca6ea1SDimitry Andric 401*0fca6ea1SDimitry Andric // Assigns `Loc` as the result object location of `E`, then propagates the 402*0fca6ea1SDimitry Andric // location to all lower-level prvalues that initialize the same object as 403*0fca6ea1SDimitry Andric // `E` (or one of its base classes or member variables). 404*0fca6ea1SDimitry Andric void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) { 405*0fca6ea1SDimitry Andric if (!E->isPRValue() || !E->getType()->isRecordType()) { 406*0fca6ea1SDimitry Andric assert(false); 407*0fca6ea1SDimitry Andric // Ensure we don't propagate the result object if we hit this in a 408*0fca6ea1SDimitry Andric // release build. 409*0fca6ea1SDimitry Andric return; 410*0fca6ea1SDimitry Andric } 411*0fca6ea1SDimitry Andric 412*0fca6ea1SDimitry Andric ResultObjectMap[E] = Loc; 413*0fca6ea1SDimitry Andric 414*0fca6ea1SDimitry Andric // The following AST node kinds are "original initializers": They are the 415*0fca6ea1SDimitry Andric // lowest-level AST node that initializes a given object, and nothing 416*0fca6ea1SDimitry Andric // below them can initialize the same object (or part of it). 417*0fca6ea1SDimitry Andric if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) || 418*0fca6ea1SDimitry Andric isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) || 419*0fca6ea1SDimitry Andric isa<AtomicExpr>(E) || 420*0fca6ea1SDimitry Andric // We treat `BuiltinBitCastExpr` as an "original initializer" too as 421*0fca6ea1SDimitry Andric // it may not even be casting from a record type -- and even if it is, 422*0fca6ea1SDimitry Andric // the two objects are in general of unrelated type. 423*0fca6ea1SDimitry Andric isa<BuiltinBitCastExpr>(E)) { 424*0fca6ea1SDimitry Andric return; 425*0fca6ea1SDimitry Andric } 426*0fca6ea1SDimitry Andric if (auto *Op = dyn_cast<BinaryOperator>(E); 427*0fca6ea1SDimitry Andric Op && Op->getOpcode() == BO_Cmp) { 428*0fca6ea1SDimitry Andric // Builtin `<=>` returns a `std::strong_ordering` object. 429*0fca6ea1SDimitry Andric return; 430*0fca6ea1SDimitry Andric } 431*0fca6ea1SDimitry Andric 432*0fca6ea1SDimitry Andric if (auto *InitList = dyn_cast<InitListExpr>(E)) { 433*0fca6ea1SDimitry Andric if (!InitList->isSemanticForm()) 434*0fca6ea1SDimitry Andric return; 435*0fca6ea1SDimitry Andric if (InitList->isTransparent()) { 436*0fca6ea1SDimitry Andric PropagateResultObject(InitList->getInit(0), Loc); 437*0fca6ea1SDimitry Andric return; 438*0fca6ea1SDimitry Andric } 439*0fca6ea1SDimitry Andric 440*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList), 441*0fca6ea1SDimitry Andric Loc); 442*0fca6ea1SDimitry Andric return; 443*0fca6ea1SDimitry Andric } 444*0fca6ea1SDimitry Andric 445*0fca6ea1SDimitry Andric if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) { 446*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList), 447*0fca6ea1SDimitry Andric Loc); 448*0fca6ea1SDimitry Andric return; 449*0fca6ea1SDimitry Andric } 450*0fca6ea1SDimitry Andric 451*0fca6ea1SDimitry Andric if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) { 452*0fca6ea1SDimitry Andric PropagateResultObject(Op->getRHS(), Loc); 453*0fca6ea1SDimitry Andric return; 454*0fca6ea1SDimitry Andric } 455*0fca6ea1SDimitry Andric 456*0fca6ea1SDimitry Andric if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) { 457*0fca6ea1SDimitry Andric PropagateResultObject(Cond->getTrueExpr(), Loc); 458*0fca6ea1SDimitry Andric PropagateResultObject(Cond->getFalseExpr(), Loc); 459*0fca6ea1SDimitry Andric return; 460*0fca6ea1SDimitry Andric } 461*0fca6ea1SDimitry Andric 462*0fca6ea1SDimitry Andric if (auto *SE = dyn_cast<StmtExpr>(E)) { 463*0fca6ea1SDimitry Andric PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc); 464*0fca6ea1SDimitry Andric return; 465*0fca6ea1SDimitry Andric } 466*0fca6ea1SDimitry Andric 467*0fca6ea1SDimitry Andric if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) { 468*0fca6ea1SDimitry Andric PropagateResultObject(DIE->getExpr(), Loc); 469*0fca6ea1SDimitry Andric return; 470*0fca6ea1SDimitry Andric } 471*0fca6ea1SDimitry Andric 472*0fca6ea1SDimitry Andric // All other expression nodes that propagate a record prvalue should have 473*0fca6ea1SDimitry Andric // exactly one child. 474*0fca6ea1SDimitry Andric SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end()); 475*0fca6ea1SDimitry Andric LLVM_DEBUG({ 476*0fca6ea1SDimitry Andric if (Children.size() != 1) 477*0fca6ea1SDimitry Andric E->dump(); 478*0fca6ea1SDimitry Andric }); 479*0fca6ea1SDimitry Andric assert(Children.size() == 1); 480*0fca6ea1SDimitry Andric for (Stmt *S : Children) 481*0fca6ea1SDimitry Andric PropagateResultObject(cast<Expr>(S), Loc); 482*0fca6ea1SDimitry Andric } 483*0fca6ea1SDimitry Andric 484*0fca6ea1SDimitry Andric private: 485*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap; 486*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal; 487*0fca6ea1SDimitry Andric DataflowAnalysisContext &DACtx; 488*0fca6ea1SDimitry Andric }; 489*0fca6ea1SDimitry Andric 490*0fca6ea1SDimitry Andric } // namespace 491*0fca6ea1SDimitry Andric 4925f757f3fSDimitry Andric void Environment::initialize() { 493*0fca6ea1SDimitry Andric if (InitialTargetStmt == nullptr) 4945f757f3fSDimitry Andric return; 4955f757f3fSDimitry Andric 496*0fca6ea1SDimitry Andric if (InitialTargetFunc == nullptr) { 497*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt)); 498*0fca6ea1SDimitry Andric ResultObjectMap = 499*0fca6ea1SDimitry Andric std::make_shared<PrValueToResultObject>(buildResultObjectMap( 500*0fca6ea1SDimitry Andric DACtx, InitialTargetStmt, getThisPointeeStorageLocation(), 501*0fca6ea1SDimitry Andric /*LocForRecordReturnValue=*/nullptr)); 502*0fca6ea1SDimitry Andric return; 503*0fca6ea1SDimitry Andric } 5045f757f3fSDimitry Andric 505*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc)); 5065f757f3fSDimitry Andric 507*0fca6ea1SDimitry Andric for (const auto *ParamDecl : InitialTargetFunc->parameters()) { 5085f757f3fSDimitry Andric assert(ParamDecl != nullptr); 5095f757f3fSDimitry Andric setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); 5105f757f3fSDimitry Andric } 5115f757f3fSDimitry Andric 512*0fca6ea1SDimitry Andric if (InitialTargetFunc->getReturnType()->isRecordType()) 513*0fca6ea1SDimitry Andric LocForRecordReturnVal = &cast<RecordStorageLocation>( 514*0fca6ea1SDimitry Andric createStorageLocation(InitialTargetFunc->getReturnType())); 515*0fca6ea1SDimitry Andric 516*0fca6ea1SDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) { 5175f757f3fSDimitry Andric auto *Parent = MethodDecl->getParent(); 5185f757f3fSDimitry Andric assert(Parent != nullptr); 5195f757f3fSDimitry Andric 5205f757f3fSDimitry Andric if (Parent->isLambda()) { 521*0fca6ea1SDimitry Andric for (const auto &Capture : Parent->captures()) { 5225f757f3fSDimitry Andric if (Capture.capturesVariable()) { 5235f757f3fSDimitry Andric const auto *VarDecl = Capture.getCapturedVar(); 5245f757f3fSDimitry Andric assert(VarDecl != nullptr); 5255f757f3fSDimitry Andric setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr)); 5265f757f3fSDimitry Andric } else if (Capture.capturesThis()) { 527*0fca6ea1SDimitry Andric if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) { 528*0fca6ea1SDimitry Andric const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor); 5295f757f3fSDimitry Andric QualType ThisPointeeType = 5305f757f3fSDimitry Andric SurroundingMethodDecl->getFunctionObjectParameterType(); 5315f757f3fSDimitry Andric setThisPointeeStorageLocation( 532*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createObject(ThisPointeeType))); 533*0fca6ea1SDimitry Andric } else if (auto *FieldBeingInitialized = 534*0fca6ea1SDimitry Andric dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) { 535*0fca6ea1SDimitry Andric // This is in a field initializer, rather than a method. 536*0fca6ea1SDimitry Andric setThisPointeeStorageLocation( 537*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createObject(QualType( 538*0fca6ea1SDimitry Andric FieldBeingInitialized->getParent()->getTypeForDecl(), 0)))); 539*0fca6ea1SDimitry Andric } else { 540*0fca6ea1SDimitry Andric assert(false && "Unexpected this-capturing lambda context."); 541*0fca6ea1SDimitry Andric } 5425f757f3fSDimitry Andric } 5435f757f3fSDimitry Andric } 5445f757f3fSDimitry Andric } else if (MethodDecl->isImplicitObjectMemberFunction()) { 5455f757f3fSDimitry Andric QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType(); 546*0fca6ea1SDimitry Andric auto &ThisLoc = 547*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType)); 548*0fca6ea1SDimitry Andric setThisPointeeStorageLocation(ThisLoc); 549*0fca6ea1SDimitry Andric // Initialize fields of `*this` with values, but only if we're not 550*0fca6ea1SDimitry Andric // analyzing a constructor; after all, it's the constructor's job to do 551*0fca6ea1SDimitry Andric // this (and we want to be able to test that). 552*0fca6ea1SDimitry Andric if (!isa<CXXConstructorDecl>(MethodDecl)) 553*0fca6ea1SDimitry Andric initializeFieldsWithValues(ThisLoc); 5545f757f3fSDimitry Andric } 5555f757f3fSDimitry Andric } 5565f757f3fSDimitry Andric 557*0fca6ea1SDimitry Andric // We do this below the handling of `CXXMethodDecl` above so that we can 558*0fca6ea1SDimitry Andric // be sure that the storage location for `this` has been set. 559*0fca6ea1SDimitry Andric ResultObjectMap = 560*0fca6ea1SDimitry Andric std::make_shared<PrValueToResultObject>(buildResultObjectMap( 561*0fca6ea1SDimitry Andric DACtx, InitialTargetFunc, getThisPointeeStorageLocation(), 562*0fca6ea1SDimitry Andric LocForRecordReturnVal)); 56306c3fb27SDimitry Andric } 56406c3fb27SDimitry Andric 565*0fca6ea1SDimitry Andric // FIXME: Add support for resetting globals after function calls to enable the 566*0fca6ea1SDimitry Andric // implementation of sound analyses. 567*0fca6ea1SDimitry Andric 568*0fca6ea1SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) { 56906c3fb27SDimitry Andric // These have to be added before the lines that follow to ensure that 57006c3fb27SDimitry Andric // `create*` work correctly for structs. 571*0fca6ea1SDimitry Andric DACtx->addModeledFields(Referenced.Fields); 57206c3fb27SDimitry Andric 573*0fca6ea1SDimitry Andric for (const VarDecl *D : Referenced.Globals) { 57406c3fb27SDimitry Andric if (getStorageLocation(*D) != nullptr) 575bdd1243dSDimitry Andric continue; 57606c3fb27SDimitry Andric 577*0fca6ea1SDimitry Andric // We don't run transfer functions on the initializers of global variables, 578*0fca6ea1SDimitry Andric // so they won't be associated with a value or storage location. We 579*0fca6ea1SDimitry Andric // therefore intentionally don't pass an initializer to `createObject()`; in 580*0fca6ea1SDimitry Andric // particular, this ensures that `createObject()` will initialize the fields 581*0fca6ea1SDimitry Andric // of record-type variables with values. 582*0fca6ea1SDimitry Andric setStorageLocation(*D, createObject(*D, nullptr)); 58306c3fb27SDimitry Andric } 58406c3fb27SDimitry Andric 585*0fca6ea1SDimitry Andric for (const FunctionDecl *FD : Referenced.Functions) { 58606c3fb27SDimitry Andric if (getStorageLocation(*FD) != nullptr) 58706c3fb27SDimitry Andric continue; 588*0fca6ea1SDimitry Andric auto &Loc = createStorageLocation(*FD); 58906c3fb27SDimitry Andric setStorageLocation(*FD, Loc); 59081ad6265SDimitry Andric } 59181ad6265SDimitry Andric } 59281ad6265SDimitry Andric 59306c3fb27SDimitry Andric Environment Environment::fork() const { 59406c3fb27SDimitry Andric Environment Copy(*this); 59506c3fb27SDimitry Andric Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken); 59606c3fb27SDimitry Andric return Copy; 5971fd87a68SDimitry Andric } 5981fd87a68SDimitry Andric 599bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth, 600*0fca6ea1SDimitry Andric const FunctionDecl *Callee) const { 601*0fca6ea1SDimitry Andric return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee); 60204eeddc0SDimitry Andric } 60304eeddc0SDimitry Andric 604972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const { 605972a253aSDimitry Andric Environment Env(*this); 606972a253aSDimitry Andric 607bdd1243dSDimitry Andric if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) { 608bdd1243dSDimitry Andric if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { 609bdd1243dSDimitry Andric if (!isa<CXXThisExpr>(Arg)) 6105f757f3fSDimitry Andric Env.ThisPointeeLoc = 6115f757f3fSDimitry Andric cast<RecordStorageLocation>(getStorageLocation(*Arg)); 612bdd1243dSDimitry Andric // Otherwise (when the argument is `this`), retain the current 613bdd1243dSDimitry Andric // environment's `ThisPointeeLoc`. 614bdd1243dSDimitry Andric } 615bdd1243dSDimitry Andric } 616972a253aSDimitry Andric 617*0fca6ea1SDimitry Andric if (Call->getType()->isRecordType() && Call->isPRValue()) 618*0fca6ea1SDimitry Andric Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); 619*0fca6ea1SDimitry Andric 620bdd1243dSDimitry Andric Env.pushCallInternal(Call->getDirectCallee(), 621bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 622bdd1243dSDimitry Andric 623bdd1243dSDimitry Andric return Env; 624bdd1243dSDimitry Andric } 625bdd1243dSDimitry Andric 626bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const { 627bdd1243dSDimitry Andric Environment Env(*this); 628bdd1243dSDimitry Andric 62906c3fb27SDimitry Andric Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); 630*0fca6ea1SDimitry Andric Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); 631bdd1243dSDimitry Andric 632bdd1243dSDimitry Andric Env.pushCallInternal(Call->getConstructor(), 633bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 634bdd1243dSDimitry Andric 635bdd1243dSDimitry Andric return Env; 636bdd1243dSDimitry Andric } 637bdd1243dSDimitry Andric 638bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl, 639bdd1243dSDimitry Andric ArrayRef<const Expr *> Args) { 64006c3fb27SDimitry Andric // Canonicalize to the definition of the function. This ensures that we're 64106c3fb27SDimitry Andric // putting arguments into the same `ParamVarDecl`s` that the callee will later 64206c3fb27SDimitry Andric // be retrieving them from. 64306c3fb27SDimitry Andric assert(FuncDecl->getDefinition() != nullptr); 64406c3fb27SDimitry Andric FuncDecl = FuncDecl->getDefinition(); 64506c3fb27SDimitry Andric 646bdd1243dSDimitry Andric CallStack.push_back(FuncDecl); 647bdd1243dSDimitry Andric 648*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl)); 649bdd1243dSDimitry Andric 650bdd1243dSDimitry Andric const auto *ParamIt = FuncDecl->param_begin(); 651972a253aSDimitry Andric 652972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include 653972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs. 654bdd1243dSDimitry Andric for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) { 655972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end()); 656972a253aSDimitry Andric const VarDecl *Param = *ParamIt; 65706c3fb27SDimitry Andric setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); 658bdd1243dSDimitry Andric } 659*0fca6ea1SDimitry Andric 660*0fca6ea1SDimitry Andric ResultObjectMap = std::make_shared<PrValueToResultObject>( 661*0fca6ea1SDimitry Andric buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), 662*0fca6ea1SDimitry Andric LocForRecordReturnVal)); 663972a253aSDimitry Andric } 664972a253aSDimitry Andric 66506c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { 6665f757f3fSDimitry Andric // We ignore some entries of `CalleeEnv`: 6675f757f3fSDimitry Andric // - `DACtx` because is already the same in both 6685f757f3fSDimitry Andric // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or 6695f757f3fSDimitry Andric // `ThisPointeeLoc` because they don't apply to us. 6705f757f3fSDimitry Andric // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the 6715f757f3fSDimitry Andric // callee's local scope, so when popping that scope, we do not propagate 6725f757f3fSDimitry Andric // the maps. 673bdd1243dSDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 674bdd1243dSDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 67506c3fb27SDimitry Andric 67606c3fb27SDimitry Andric if (Call->isGLValue()) { 67706c3fb27SDimitry Andric if (CalleeEnv.ReturnLoc != nullptr) 6785f757f3fSDimitry Andric setStorageLocation(*Call, *CalleeEnv.ReturnLoc); 67906c3fb27SDimitry Andric } else if (!Call->getType()->isVoidType()) { 68006c3fb27SDimitry Andric if (CalleeEnv.ReturnVal != nullptr) 6815f757f3fSDimitry Andric setValue(*Call, *CalleeEnv.ReturnVal); 68206c3fb27SDimitry Andric } 68306c3fb27SDimitry Andric } 68406c3fb27SDimitry Andric 68506c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call, 68606c3fb27SDimitry Andric const Environment &CalleeEnv) { 68706c3fb27SDimitry Andric // See also comment in `popCall(const CallExpr *, const Environment &)` above. 68806c3fb27SDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 68906c3fb27SDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 690972a253aSDimitry Andric } 691972a253aSDimitry Andric 6921fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 6931fd87a68SDimitry Andric Environment::ValueModel &Model) const { 69404eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 6951fd87a68SDimitry Andric 69606c3fb27SDimitry Andric if (ReturnVal != Other.ReturnVal) 69706c3fb27SDimitry Andric return false; 69806c3fb27SDimitry Andric 699bdd1243dSDimitry Andric if (ReturnLoc != Other.ReturnLoc) 700bdd1243dSDimitry Andric return false; 701bdd1243dSDimitry Andric 702*0fca6ea1SDimitry Andric if (LocForRecordReturnVal != Other.LocForRecordReturnVal) 703*0fca6ea1SDimitry Andric return false; 704*0fca6ea1SDimitry Andric 705bdd1243dSDimitry Andric if (ThisPointeeLoc != Other.ThisPointeeLoc) 706bdd1243dSDimitry Andric return false; 707bdd1243dSDimitry Andric 7081fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 7091fd87a68SDimitry Andric return false; 7101fd87a68SDimitry Andric 7111fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 7121fd87a68SDimitry Andric return false; 7131fd87a68SDimitry Andric 7145f757f3fSDimitry Andric if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model)) 7151fd87a68SDimitry Andric return false; 7165f757f3fSDimitry Andric 7175f757f3fSDimitry Andric if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model)) 7185f757f3fSDimitry Andric return false; 7191fd87a68SDimitry Andric 7201fd87a68SDimitry Andric return true; 72104eeddc0SDimitry Andric } 72204eeddc0SDimitry Andric 723*0fca6ea1SDimitry Andric LatticeEffect Environment::widen(const Environment &PrevEnv, 724bdd1243dSDimitry Andric Environment::ValueModel &Model) { 725bdd1243dSDimitry Andric assert(DACtx == PrevEnv.DACtx); 72606c3fb27SDimitry Andric assert(ReturnVal == PrevEnv.ReturnVal); 727bdd1243dSDimitry Andric assert(ReturnLoc == PrevEnv.ReturnLoc); 728*0fca6ea1SDimitry Andric assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal); 729bdd1243dSDimitry Andric assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); 730bdd1243dSDimitry Andric assert(CallStack == PrevEnv.CallStack); 731*0fca6ea1SDimitry Andric assert(ResultObjectMap == PrevEnv.ResultObjectMap); 732*0fca6ea1SDimitry Andric assert(InitialTargetFunc == PrevEnv.InitialTargetFunc); 733*0fca6ea1SDimitry Andric assert(InitialTargetStmt == PrevEnv.InitialTargetStmt); 734bdd1243dSDimitry Andric 735*0fca6ea1SDimitry Andric auto Effect = LatticeEffect::Unchanged; 736bdd1243dSDimitry Andric 737bdd1243dSDimitry Andric // By the API, `PrevEnv` is a previous version of the environment for the same 738bdd1243dSDimitry Andric // block, so we have some guarantees about its shape. In particular, it will 739bdd1243dSDimitry Andric // be the result of a join or widen operation on previous values for this 7405f757f3fSDimitry Andric // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that 7415f757f3fSDimitry Andric // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain 7425f757f3fSDimitry Andric // this property here, we don't need change their current values to widen. 743bdd1243dSDimitry Andric assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size()); 7445f757f3fSDimitry Andric assert(ExprToVal.size() <= PrevEnv.ExprToVal.size()); 745bdd1243dSDimitry Andric assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size()); 746bdd1243dSDimitry Andric 7475f757f3fSDimitry Andric ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv, 7485f757f3fSDimitry Andric Model, Effect); 749bdd1243dSDimitry Andric 7505f757f3fSDimitry Andric LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv, 7515f757f3fSDimitry Andric Model, Effect); 752bdd1243dSDimitry Andric if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() || 753bdd1243dSDimitry Andric ExprToLoc.size() != PrevEnv.ExprToLoc.size() || 7545f757f3fSDimitry Andric ExprToVal.size() != PrevEnv.ExprToVal.size() || 75506c3fb27SDimitry Andric LocToVal.size() != PrevEnv.LocToVal.size()) 756*0fca6ea1SDimitry Andric Effect = LatticeEffect::Changed; 757bdd1243dSDimitry Andric 758bdd1243dSDimitry Andric return Effect; 759bdd1243dSDimitry Andric } 760bdd1243dSDimitry Andric 76106c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB, 762*0fca6ea1SDimitry Andric Environment::ValueModel &Model, 763*0fca6ea1SDimitry Andric ExprJoinBehavior ExprBehavior) { 76406c3fb27SDimitry Andric assert(EnvA.DACtx == EnvB.DACtx); 765*0fca6ea1SDimitry Andric assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal); 76606c3fb27SDimitry Andric assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); 76706c3fb27SDimitry Andric assert(EnvA.CallStack == EnvB.CallStack); 768*0fca6ea1SDimitry Andric assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap); 769*0fca6ea1SDimitry Andric assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc); 770*0fca6ea1SDimitry Andric assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt); 77104eeddc0SDimitry Andric 77206c3fb27SDimitry Andric Environment JoinedEnv(*EnvA.DACtx); 77304eeddc0SDimitry Andric 77406c3fb27SDimitry Andric JoinedEnv.CallStack = EnvA.CallStack; 775*0fca6ea1SDimitry Andric JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap; 776*0fca6ea1SDimitry Andric JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal; 77706c3fb27SDimitry Andric JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; 778*0fca6ea1SDimitry Andric JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc; 779*0fca6ea1SDimitry Andric JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt; 78081ad6265SDimitry Andric 781*0fca6ea1SDimitry Andric const FunctionDecl *Func = EnvA.getCurrentFunc(); 782*0fca6ea1SDimitry Andric if (!Func) { 78306c3fb27SDimitry Andric JoinedEnv.ReturnVal = nullptr; 78406c3fb27SDimitry Andric } else { 785*0fca6ea1SDimitry Andric JoinedEnv.ReturnVal = 786*0fca6ea1SDimitry Andric joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal, 787*0fca6ea1SDimitry Andric EnvB, JoinedEnv, Model); 78806c3fb27SDimitry Andric } 789bdd1243dSDimitry Andric 79006c3fb27SDimitry Andric if (EnvA.ReturnLoc == EnvB.ReturnLoc) 79106c3fb27SDimitry Andric JoinedEnv.ReturnLoc = EnvA.ReturnLoc; 79206c3fb27SDimitry Andric else 79306c3fb27SDimitry Andric JoinedEnv.ReturnLoc = nullptr; 79404eeddc0SDimitry Andric 7955f757f3fSDimitry Andric JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc); 79681ad6265SDimitry Andric 797bdd1243dSDimitry Andric // FIXME: update join to detect backedges and simplify the flow condition 798bdd1243dSDimitry Andric // accordingly. 79906c3fb27SDimitry Andric JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions( 80006c3fb27SDimitry Andric EnvA.FlowConditionToken, EnvB.FlowConditionToken); 80181ad6265SDimitry Andric 8025f757f3fSDimitry Andric JoinedEnv.LocToVal = 8035f757f3fSDimitry Andric joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model); 80404eeddc0SDimitry Andric 805*0fca6ea1SDimitry Andric if (ExprBehavior == KeepExprState) { 806*0fca6ea1SDimitry Andric JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal); 807*0fca6ea1SDimitry Andric JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc); 808*0fca6ea1SDimitry Andric } 80904eeddc0SDimitry Andric 81006c3fb27SDimitry Andric return JoinedEnv; 81104eeddc0SDimitry Andric } 81204eeddc0SDimitry Andric 813*0fca6ea1SDimitry Andric Value *Environment::joinValues(QualType Ty, Value *Val1, 814*0fca6ea1SDimitry Andric const Environment &Env1, Value *Val2, 815*0fca6ea1SDimitry Andric const Environment &Env2, Environment &JoinedEnv, 816*0fca6ea1SDimitry Andric Environment::ValueModel &Model) { 817*0fca6ea1SDimitry Andric if (Val1 == nullptr || Val2 == nullptr) 818*0fca6ea1SDimitry Andric // We can't say anything about the joined value -- even if one of the values 819*0fca6ea1SDimitry Andric // is non-null, we don't want to simply propagate it, because it would be 820*0fca6ea1SDimitry Andric // too specific: Because the other value is null, that means we have no 821*0fca6ea1SDimitry Andric // information at all about the value (i.e. the value is unconstrained). 822*0fca6ea1SDimitry Andric return nullptr; 823*0fca6ea1SDimitry Andric 824*0fca6ea1SDimitry Andric if (areEquivalentValues(*Val1, *Val2)) 825*0fca6ea1SDimitry Andric // Arbitrarily return one of the two values. 826*0fca6ea1SDimitry Andric return Val1; 827*0fca6ea1SDimitry Andric 828*0fca6ea1SDimitry Andric return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model); 829*0fca6ea1SDimitry Andric } 830*0fca6ea1SDimitry Andric 83104eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 832bdd1243dSDimitry Andric return DACtx->createStorageLocation(Type); 83304eeddc0SDimitry Andric } 83404eeddc0SDimitry Andric 8355f757f3fSDimitry Andric StorageLocation &Environment::createStorageLocation(const ValueDecl &D) { 83604eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 83704eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 83804eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 83981ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 84004eeddc0SDimitry Andric } 84104eeddc0SDimitry Andric 84204eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 84304eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 84404eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 84504eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 84681ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 84704eeddc0SDimitry Andric } 84804eeddc0SDimitry Andric 84904eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 85006c3fb27SDimitry Andric assert(!DeclToLoc.contains(&D)); 851*0fca6ea1SDimitry Andric // The only kinds of declarations that may have a "variable" storage location 852*0fca6ea1SDimitry Andric // are declarations of reference type and `BindingDecl`. For all other 853*0fca6ea1SDimitry Andric // declaration, the storage location should be the stable storage location 854*0fca6ea1SDimitry Andric // returned by `createStorageLocation()`. 855*0fca6ea1SDimitry Andric assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) || 856*0fca6ea1SDimitry Andric &Loc == &createStorageLocation(D)); 85704eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 85804eeddc0SDimitry Andric } 85904eeddc0SDimitry Andric 86006c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 86104eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 86206c3fb27SDimitry Andric if (It == DeclToLoc.end()) 86306c3fb27SDimitry Andric return nullptr; 86406c3fb27SDimitry Andric 86506c3fb27SDimitry Andric StorageLocation *Loc = It->second; 86606c3fb27SDimitry Andric 86706c3fb27SDimitry Andric return Loc; 86804eeddc0SDimitry Andric } 86904eeddc0SDimitry Andric 8705f757f3fSDimitry Andric void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); } 87104eeddc0SDimitry Andric 8725f757f3fSDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 87306c3fb27SDimitry Andric // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason, 87406c3fb27SDimitry Andric // but we still want to be able to associate a `StorageLocation` with them, 87506c3fb27SDimitry Andric // so allow these as an exception. 87606c3fb27SDimitry Andric assert(E.isGLValue() || 87706c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 878cb14a3feSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 879cb14a3feSDimitry Andric assert(!ExprToLoc.contains(&CanonE)); 880cb14a3feSDimitry Andric ExprToLoc[&CanonE] = &Loc; 88106c3fb27SDimitry Andric } 88206c3fb27SDimitry Andric 8835f757f3fSDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E) const { 8845f757f3fSDimitry Andric // See comment in `setStorageLocation()`. 88506c3fb27SDimitry Andric assert(E.isGLValue() || 88606c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 887cb14a3feSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 888cb14a3feSDimitry Andric return It == ExprToLoc.end() ? nullptr : &*It->second; 889cb14a3feSDimitry Andric } 890cb14a3feSDimitry Andric 8915f757f3fSDimitry Andric RecordStorageLocation & 892cb14a3feSDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) const { 89306c3fb27SDimitry Andric assert(RecordPRValue.getType()->isRecordType()); 89406c3fb27SDimitry Andric assert(RecordPRValue.isPRValue()); 89506c3fb27SDimitry Andric 896*0fca6ea1SDimitry Andric assert(ResultObjectMap != nullptr); 897*0fca6ea1SDimitry Andric RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue); 898*0fca6ea1SDimitry Andric assert(Loc != nullptr); 899*0fca6ea1SDimitry Andric // In release builds, use the "stable" storage location if the map lookup 900*0fca6ea1SDimitry Andric // failed. 901*0fca6ea1SDimitry Andric if (Loc == nullptr) 902cb14a3feSDimitry Andric return cast<RecordStorageLocation>( 90306c3fb27SDimitry Andric DACtx->getStableStorageLocation(RecordPRValue)); 904*0fca6ea1SDimitry Andric return *Loc; 90504eeddc0SDimitry Andric } 90604eeddc0SDimitry Andric 90781ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 90881ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 90981ad6265SDimitry Andric } 91081ad6265SDimitry Andric 911*0fca6ea1SDimitry Andric void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, 912*0fca6ea1SDimitry Andric QualType Type) { 913*0fca6ea1SDimitry Andric llvm::DenseSet<QualType> Visited; 914*0fca6ea1SDimitry Andric int CreatedValuesCount = 0; 915*0fca6ea1SDimitry Andric initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount); 916*0fca6ea1SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 917*0fca6ea1SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 918*0fca6ea1SDimitry Andric << '\n'; 919*0fca6ea1SDimitry Andric } 920*0fca6ea1SDimitry Andric } 92106c3fb27SDimitry Andric 922*0fca6ea1SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 923*0fca6ea1SDimitry Andric // Records should not be associated with values. 924*0fca6ea1SDimitry Andric assert(!isa<RecordStorageLocation>(Loc)); 92504eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 92606c3fb27SDimitry Andric } 92706c3fb27SDimitry Andric 9285f757f3fSDimitry Andric void Environment::setValue(const Expr &E, Value &Val) { 9297a6dacacSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 9307a6dacacSDimitry Andric 9317a6dacacSDimitry Andric assert(CanonE.isPRValue()); 932*0fca6ea1SDimitry Andric // Records should not be associated with values. 933*0fca6ea1SDimitry Andric assert(!CanonE.getType()->isRecordType()); 9347a6dacacSDimitry Andric ExprToVal[&CanonE] = &Val; 93504eeddc0SDimitry Andric } 93604eeddc0SDimitry Andric 93704eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 938*0fca6ea1SDimitry Andric // Records should not be associated with values. 939*0fca6ea1SDimitry Andric assert(!isa<RecordStorageLocation>(Loc)); 94006c3fb27SDimitry Andric return LocToVal.lookup(&Loc); 94104eeddc0SDimitry Andric } 94204eeddc0SDimitry Andric 94306c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const { 94406c3fb27SDimitry Andric auto *Loc = getStorageLocation(D); 94504eeddc0SDimitry Andric if (Loc == nullptr) 94604eeddc0SDimitry Andric return nullptr; 94704eeddc0SDimitry Andric return getValue(*Loc); 94804eeddc0SDimitry Andric } 94904eeddc0SDimitry Andric 9505f757f3fSDimitry Andric Value *Environment::getValue(const Expr &E) const { 951*0fca6ea1SDimitry Andric // Records should not be associated with values. 952*0fca6ea1SDimitry Andric assert(!E.getType()->isRecordType()); 953*0fca6ea1SDimitry Andric 9545f757f3fSDimitry Andric if (E.isPRValue()) { 9555f757f3fSDimitry Andric auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E)); 9565f757f3fSDimitry Andric return It == ExprToVal.end() ? nullptr : It->second; 95704eeddc0SDimitry Andric } 95804eeddc0SDimitry Andric 9595f757f3fSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 9605f757f3fSDimitry Andric if (It == ExprToLoc.end()) 9615f757f3fSDimitry Andric return nullptr; 9625f757f3fSDimitry Andric return getValue(*It->second); 96306c3fb27SDimitry Andric } 96406c3fb27SDimitry Andric 96504eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 96604eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 96781ad6265SDimitry Andric int CreatedValuesCount = 0; 96881ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 96981ad6265SDimitry Andric CreatedValuesCount); 97081ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 97181ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 97281ad6265SDimitry Andric << '\n'; 97381ad6265SDimitry Andric } 97481ad6265SDimitry Andric return Val; 97504eeddc0SDimitry Andric } 97604eeddc0SDimitry Andric 97704eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 97881ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 97981ad6265SDimitry Andric int &CreatedValuesCount) { 98004eeddc0SDimitry Andric assert(!Type.isNull()); 9815f757f3fSDimitry Andric assert(!Type->isReferenceType()); 982*0fca6ea1SDimitry Andric assert(!Type->isRecordType()); 98304eeddc0SDimitry Andric 98481ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 98581ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 98681ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 98781ad6265SDimitry Andric return nullptr; 98881ad6265SDimitry Andric 98981ad6265SDimitry Andric if (Type->isBooleanType()) { 99081ad6265SDimitry Andric CreatedValuesCount++; 99181ad6265SDimitry Andric return &makeAtomicBoolValue(); 99281ad6265SDimitry Andric } 99381ad6265SDimitry Andric 99404eeddc0SDimitry Andric if (Type->isIntegerType()) { 995bdd1243dSDimitry Andric // FIXME: consider instead `return nullptr`, given that we do nothing useful 996bdd1243dSDimitry Andric // with integers, and so distinguishing them serves no purpose, but could 997bdd1243dSDimitry Andric // prevent convergence. 99881ad6265SDimitry Andric CreatedValuesCount++; 99906c3fb27SDimitry Andric return &arena().create<IntegerValue>(); 100004eeddc0SDimitry Andric } 100104eeddc0SDimitry Andric 10025f757f3fSDimitry Andric if (Type->isPointerType()) { 100381ad6265SDimitry Andric CreatedValuesCount++; 100406c3fb27SDimitry Andric QualType PointeeType = Type->getPointeeType(); 100506c3fb27SDimitry Andric StorageLocation &PointeeLoc = 100606c3fb27SDimitry Andric createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); 100704eeddc0SDimitry Andric 100806c3fb27SDimitry Andric return &arena().create<PointerValue>(PointeeLoc); 100904eeddc0SDimitry Andric } 101004eeddc0SDimitry Andric 101104eeddc0SDimitry Andric return nullptr; 101204eeddc0SDimitry Andric } 101304eeddc0SDimitry Andric 101406c3fb27SDimitry Andric StorageLocation & 101506c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty, 101606c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited, 101706c3fb27SDimitry Andric int Depth, int &CreatedValuesCount) { 101806c3fb27SDimitry Andric if (!Visited.insert(Ty.getCanonicalType()).second) 101906c3fb27SDimitry Andric return createStorageLocation(Ty.getNonReferenceType()); 1020*0fca6ea1SDimitry Andric auto EraseVisited = llvm::make_scope_exit( 1021*0fca6ea1SDimitry Andric [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); }); 102206c3fb27SDimitry Andric 102306c3fb27SDimitry Andric Ty = Ty.getNonReferenceType(); 102406c3fb27SDimitry Andric 1025*0fca6ea1SDimitry Andric if (Ty->isRecordType()) { 1026*0fca6ea1SDimitry Andric auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty)); 1027*0fca6ea1SDimitry Andric initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount); 1028*0fca6ea1SDimitry Andric return Loc; 1029*0fca6ea1SDimitry Andric } 103006c3fb27SDimitry Andric 103106c3fb27SDimitry Andric StorageLocation &Loc = createStorageLocation(Ty); 1032*0fca6ea1SDimitry Andric 1033*0fca6ea1SDimitry Andric if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth, 1034*0fca6ea1SDimitry Andric CreatedValuesCount)) 103506c3fb27SDimitry Andric setValue(Loc, *Val); 1036*0fca6ea1SDimitry Andric 103706c3fb27SDimitry Andric return Loc; 103806c3fb27SDimitry Andric } 103906c3fb27SDimitry Andric 1040*0fca6ea1SDimitry Andric void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, 1041*0fca6ea1SDimitry Andric QualType Type, 1042*0fca6ea1SDimitry Andric llvm::DenseSet<QualType> &Visited, 1043*0fca6ea1SDimitry Andric int Depth, 1044*0fca6ea1SDimitry Andric int &CreatedValuesCount) { 1045*0fca6ea1SDimitry Andric auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) { 1046*0fca6ea1SDimitry Andric if (FieldType->isRecordType()) { 1047*0fca6ea1SDimitry Andric auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc); 1048*0fca6ea1SDimitry Andric initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(), 1049*0fca6ea1SDimitry Andric Visited, Depth + 1, CreatedValuesCount); 1050*0fca6ea1SDimitry Andric } else { 1051*0fca6ea1SDimitry Andric if (getValue(FieldLoc) != nullptr) 1052*0fca6ea1SDimitry Andric return; 1053*0fca6ea1SDimitry Andric if (!Visited.insert(FieldType.getCanonicalType()).second) 1054*0fca6ea1SDimitry Andric return; 1055*0fca6ea1SDimitry Andric if (Value *Val = createValueUnlessSelfReferential( 1056*0fca6ea1SDimitry Andric FieldType, Visited, Depth + 1, CreatedValuesCount)) 1057*0fca6ea1SDimitry Andric setValue(FieldLoc, *Val); 1058*0fca6ea1SDimitry Andric Visited.erase(FieldType.getCanonicalType()); 1059*0fca6ea1SDimitry Andric } 1060*0fca6ea1SDimitry Andric }; 1061*0fca6ea1SDimitry Andric 1062*0fca6ea1SDimitry Andric for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { 1063*0fca6ea1SDimitry Andric assert(Field != nullptr); 1064*0fca6ea1SDimitry Andric QualType FieldType = Field->getType(); 1065*0fca6ea1SDimitry Andric 1066*0fca6ea1SDimitry Andric if (FieldType->isReferenceType()) { 1067*0fca6ea1SDimitry Andric Loc.setChild(*Field, 1068*0fca6ea1SDimitry Andric &createLocAndMaybeValue(FieldType, Visited, Depth + 1, 1069*0fca6ea1SDimitry Andric CreatedValuesCount)); 1070*0fca6ea1SDimitry Andric } else { 1071*0fca6ea1SDimitry Andric StorageLocation *FieldLoc = Loc.getChild(*Field); 1072*0fca6ea1SDimitry Andric assert(FieldLoc != nullptr); 1073*0fca6ea1SDimitry Andric initField(FieldType, *FieldLoc); 1074*0fca6ea1SDimitry Andric } 1075*0fca6ea1SDimitry Andric } 1076*0fca6ea1SDimitry Andric for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) { 1077*0fca6ea1SDimitry Andric // Synthetic fields cannot have reference type, so we don't need to deal 1078*0fca6ea1SDimitry Andric // with this case. 1079*0fca6ea1SDimitry Andric assert(!FieldType->isReferenceType()); 1080*0fca6ea1SDimitry Andric initField(FieldType, Loc.getSyntheticField(FieldName)); 1081*0fca6ea1SDimitry Andric } 1082*0fca6ea1SDimitry Andric } 1083*0fca6ea1SDimitry Andric 10845f757f3fSDimitry Andric StorageLocation &Environment::createObjectInternal(const ValueDecl *D, 108506c3fb27SDimitry Andric QualType Ty, 108606c3fb27SDimitry Andric const Expr *InitExpr) { 108706c3fb27SDimitry Andric if (Ty->isReferenceType()) { 108806c3fb27SDimitry Andric // Although variables of reference type always need to be initialized, it 108906c3fb27SDimitry Andric // can happen that we can't see the initializer, so `InitExpr` may still 109006c3fb27SDimitry Andric // be null. 109106c3fb27SDimitry Andric if (InitExpr) { 10925f757f3fSDimitry Andric if (auto *InitExprLoc = getStorageLocation(*InitExpr)) 109306c3fb27SDimitry Andric return *InitExprLoc; 109406c3fb27SDimitry Andric } 109506c3fb27SDimitry Andric 109606c3fb27SDimitry Andric // Even though we have an initializer, we might not get an 109706c3fb27SDimitry Andric // InitExprLoc, for example if the InitExpr is a CallExpr for which we 109806c3fb27SDimitry Andric // don't have a function body. In this case, we just invent a storage 109906c3fb27SDimitry Andric // location and value -- it's the best we can do. 110006c3fb27SDimitry Andric return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); 110106c3fb27SDimitry Andric } 110206c3fb27SDimitry Andric 1103*0fca6ea1SDimitry Andric StorageLocation &Loc = 1104*0fca6ea1SDimitry Andric D ? createStorageLocation(*D) : createStorageLocation(Ty); 1105*0fca6ea1SDimitry Andric 1106*0fca6ea1SDimitry Andric if (Ty->isRecordType()) { 1107*0fca6ea1SDimitry Andric auto &RecordLoc = cast<RecordStorageLocation>(Loc); 1108*0fca6ea1SDimitry Andric if (!InitExpr) 1109*0fca6ea1SDimitry Andric initializeFieldsWithValues(RecordLoc); 1110*0fca6ea1SDimitry Andric } else { 111106c3fb27SDimitry Andric Value *Val = nullptr; 111206c3fb27SDimitry Andric if (InitExpr) 111306c3fb27SDimitry Andric // In the (few) cases where an expression is intentionally 111406c3fb27SDimitry Andric // "uninterpreted", `InitExpr` is not associated with a value. There are 111506c3fb27SDimitry Andric // two ways to handle this situation: propagate the status, so that 111606c3fb27SDimitry Andric // uninterpreted initializers result in uninterpreted variables, or 111706c3fb27SDimitry Andric // provide a default value. We choose the latter so that later refinements 111806c3fb27SDimitry Andric // of the variable can be used for reasoning about the surrounding code. 111906c3fb27SDimitry Andric // For this reason, we let this case be handled by the `createValue()` 112006c3fb27SDimitry Andric // call below. 112106c3fb27SDimitry Andric // 112206c3fb27SDimitry Andric // FIXME. If and when we interpret all language cases, change this to 112306c3fb27SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a 112406c3fb27SDimitry Andric // default value (assuming we don't update the environment API to return 112506c3fb27SDimitry Andric // references). 11265f757f3fSDimitry Andric Val = getValue(*InitExpr); 112706c3fb27SDimitry Andric if (!Val) 112806c3fb27SDimitry Andric Val = createValue(Ty); 112906c3fb27SDimitry Andric if (Val) 113006c3fb27SDimitry Andric setValue(Loc, *Val); 1131*0fca6ea1SDimitry Andric } 113206c3fb27SDimitry Andric 113306c3fb27SDimitry Andric return Loc; 113406c3fb27SDimitry Andric } 113506c3fb27SDimitry Andric 11365f757f3fSDimitry Andric void Environment::assume(const Formula &F) { 11375f757f3fSDimitry Andric DACtx->addFlowConditionConstraint(FlowConditionToken, F); 113804eeddc0SDimitry Andric } 113904eeddc0SDimitry Andric 11405f757f3fSDimitry Andric bool Environment::proves(const Formula &F) const { 11415f757f3fSDimitry Andric return DACtx->flowConditionImplies(FlowConditionToken, F); 114204eeddc0SDimitry Andric } 114304eeddc0SDimitry Andric 11445f757f3fSDimitry Andric bool Environment::allows(const Formula &F) const { 11455f757f3fSDimitry Andric return DACtx->flowConditionAllows(FlowConditionToken, F); 114681ad6265SDimitry Andric } 114781ad6265SDimitry Andric 1148bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const { 1149*0fca6ea1SDimitry Andric llvm::DenseMap<const StorageLocation *, std::string> LocToName; 1150*0fca6ea1SDimitry Andric if (LocForRecordReturnVal != nullptr) 1151*0fca6ea1SDimitry Andric LocToName[LocForRecordReturnVal] = "(returned record)"; 1152*0fca6ea1SDimitry Andric if (ThisPointeeLoc != nullptr) 1153*0fca6ea1SDimitry Andric LocToName[ThisPointeeLoc] = "this"; 1154bdd1243dSDimitry Andric 1155*0fca6ea1SDimitry Andric OS << "DeclToLoc:\n"; 1156*0fca6ea1SDimitry Andric for (auto [D, L] : DeclToLoc) { 1157*0fca6ea1SDimitry Andric auto Iter = LocToName.insert({L, D->getNameAsString()}).first; 1158*0fca6ea1SDimitry Andric OS << " [" << Iter->second << ", " << L << "]\n"; 1159*0fca6ea1SDimitry Andric } 1160bdd1243dSDimitry Andric OS << "ExprToLoc:\n"; 1161bdd1243dSDimitry Andric for (auto [E, L] : ExprToLoc) 1162bdd1243dSDimitry Andric OS << " [" << E << ", " << L << "]\n"; 1163bdd1243dSDimitry Andric 11645f757f3fSDimitry Andric OS << "ExprToVal:\n"; 11655f757f3fSDimitry Andric for (auto [E, V] : ExprToVal) 11665f757f3fSDimitry Andric OS << " [" << E << ", " << V << ": " << *V << "]\n"; 11675f757f3fSDimitry Andric 1168bdd1243dSDimitry Andric OS << "LocToVal:\n"; 1169bdd1243dSDimitry Andric for (auto [L, V] : LocToVal) { 1170*0fca6ea1SDimitry Andric OS << " [" << L; 1171*0fca6ea1SDimitry Andric if (auto Iter = LocToName.find(L); Iter != LocToName.end()) 1172*0fca6ea1SDimitry Andric OS << " (" << Iter->second << ")"; 1173*0fca6ea1SDimitry Andric OS << ", " << V << ": " << *V << "]\n"; 1174*0fca6ea1SDimitry Andric } 1175*0fca6ea1SDimitry Andric 1176*0fca6ea1SDimitry Andric if (const FunctionDecl *Func = getCurrentFunc()) { 1177*0fca6ea1SDimitry Andric if (Func->getReturnType()->isReferenceType()) { 1178*0fca6ea1SDimitry Andric OS << "ReturnLoc: " << ReturnLoc; 1179*0fca6ea1SDimitry Andric if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end()) 1180*0fca6ea1SDimitry Andric OS << " (" << Iter->second << ")"; 1181*0fca6ea1SDimitry Andric OS << "\n"; 1182*0fca6ea1SDimitry Andric } else if (Func->getReturnType()->isRecordType() || 1183*0fca6ea1SDimitry Andric isa<CXXConstructorDecl>(Func)) { 1184*0fca6ea1SDimitry Andric OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n"; 1185*0fca6ea1SDimitry Andric } else if (!Func->getReturnType()->isVoidType()) { 1186*0fca6ea1SDimitry Andric if (ReturnVal == nullptr) 1187*0fca6ea1SDimitry Andric OS << "ReturnVal: nullptr\n"; 1188*0fca6ea1SDimitry Andric else 1189*0fca6ea1SDimitry Andric OS << "ReturnVal: " << *ReturnVal << "\n"; 1190*0fca6ea1SDimitry Andric } 1191*0fca6ea1SDimitry Andric 1192*0fca6ea1SDimitry Andric if (isa<CXXMethodDecl>(Func)) { 1193*0fca6ea1SDimitry Andric OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n"; 1194*0fca6ea1SDimitry Andric } 1195bdd1243dSDimitry Andric } 1196bdd1243dSDimitry Andric 11975f757f3fSDimitry Andric OS << "\n"; 119806c3fb27SDimitry Andric DACtx->dumpFlowCondition(FlowConditionToken, OS); 1199fcaf7f86SDimitry Andric } 1200fcaf7f86SDimitry Andric 1201*0fca6ea1SDimitry Andric void Environment::dump() const { dump(llvm::dbgs()); } 1202*0fca6ea1SDimitry Andric 1203*0fca6ea1SDimitry Andric Environment::PrValueToResultObject Environment::buildResultObjectMap( 1204*0fca6ea1SDimitry Andric DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl, 1205*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc, 1206*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal) { 1207*0fca6ea1SDimitry Andric assert(FuncDecl->doesThisDeclarationHaveABody()); 1208*0fca6ea1SDimitry Andric 1209*0fca6ea1SDimitry Andric PrValueToResultObject Map = buildResultObjectMap( 1210*0fca6ea1SDimitry Andric DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal); 1211*0fca6ea1SDimitry Andric 1212*0fca6ea1SDimitry Andric ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); 1213*0fca6ea1SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) 1214*0fca6ea1SDimitry Andric Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc); 1215*0fca6ea1SDimitry Andric 1216*0fca6ea1SDimitry Andric return Map; 1217*0fca6ea1SDimitry Andric } 1218*0fca6ea1SDimitry Andric 1219*0fca6ea1SDimitry Andric Environment::PrValueToResultObject Environment::buildResultObjectMap( 1220*0fca6ea1SDimitry Andric DataflowAnalysisContext *DACtx, Stmt *S, 1221*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc, 1222*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal) { 1223*0fca6ea1SDimitry Andric PrValueToResultObject Map; 1224*0fca6ea1SDimitry Andric ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); 1225*0fca6ea1SDimitry Andric Visitor.TraverseStmt(S); 1226*0fca6ea1SDimitry Andric return Map; 1227bdd1243dSDimitry Andric } 1228bdd1243dSDimitry Andric 12295f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 123006c3fb27SDimitry Andric const Environment &Env) { 123106c3fb27SDimitry Andric Expr *ImplicitObject = MCE.getImplicitObjectArgument(); 123206c3fb27SDimitry Andric if (ImplicitObject == nullptr) 123306c3fb27SDimitry Andric return nullptr; 123406c3fb27SDimitry Andric if (ImplicitObject->getType()->isPointerType()) { 1235cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*ImplicitObject)) 12365f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 123706c3fb27SDimitry Andric return nullptr; 123806c3fb27SDimitry Andric } 12395f757f3fSDimitry Andric return cast_or_null<RecordStorageLocation>( 12405f757f3fSDimitry Andric Env.getStorageLocation(*ImplicitObject)); 124106c3fb27SDimitry Andric } 124206c3fb27SDimitry Andric 12435f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 124406c3fb27SDimitry Andric const Environment &Env) { 124506c3fb27SDimitry Andric Expr *Base = ME.getBase(); 124606c3fb27SDimitry Andric if (Base == nullptr) 124706c3fb27SDimitry Andric return nullptr; 124806c3fb27SDimitry Andric if (ME.isArrow()) { 1249cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*Base)) 12505f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 125106c3fb27SDimitry Andric return nullptr; 125206c3fb27SDimitry Andric } 1253cb14a3feSDimitry Andric return Env.get<RecordStorageLocation>(*Base); 125406c3fb27SDimitry Andric } 125506c3fb27SDimitry Andric 125604eeddc0SDimitry Andric } // namespace dataflow 125704eeddc0SDimitry Andric } // namespace clang 1258