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*81ad6265SDimitry Andric #include "clang/AST/ExprCXX.h" 1904eeddc0SDimitry Andric #include "clang/AST/Type.h" 2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2104eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/StorageLocation.h" 2204eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2304eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 2404eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 25*81ad6265SDimitry Andric #include "llvm/Support/Casting.h" 2604eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 27*81ad6265SDimitry Andric #include <cassert> 2804eeddc0SDimitry Andric #include <memory> 2904eeddc0SDimitry Andric #include <utility> 3004eeddc0SDimitry Andric 3104eeddc0SDimitry Andric namespace clang { 3204eeddc0SDimitry Andric namespace dataflow { 3304eeddc0SDimitry Andric 34*81ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 35*81ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 36*81ad6265SDimitry Andric // analysis. 37*81ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 38*81ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 39*81ad6265SDimitry Andric 4004eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 4104eeddc0SDimitry Andric template <typename K, typename V> 4204eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 4304eeddc0SDimitry Andric const llvm::DenseMap<K, V> &Map2) { 4404eeddc0SDimitry Andric llvm::DenseMap<K, V> Result; 4504eeddc0SDimitry Andric for (auto &Entry : Map1) { 4604eeddc0SDimitry Andric auto It = Map2.find(Entry.first); 4704eeddc0SDimitry Andric if (It != Map2.end() && Entry.second == It->second) 4804eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 4904eeddc0SDimitry Andric } 5004eeddc0SDimitry Andric return Result; 5104eeddc0SDimitry Andric } 5204eeddc0SDimitry Andric 53*81ad6265SDimitry Andric static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) { 54*81ad6265SDimitry Andric if (auto *IndVal1 = dyn_cast<ReferenceValue>(Val1)) { 55*81ad6265SDimitry Andric auto *IndVal2 = cast<ReferenceValue>(Val2); 56*81ad6265SDimitry Andric return &IndVal1->getReferentLoc() == &IndVal2->getReferentLoc(); 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric if (auto *IndVal1 = dyn_cast<PointerValue>(Val1)) { 59*81ad6265SDimitry Andric auto *IndVal2 = cast<PointerValue>(Val2); 601fd87a68SDimitry Andric return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); 611fd87a68SDimitry Andric } 62*81ad6265SDimitry Andric return false; 63*81ad6265SDimitry Andric } 641fd87a68SDimitry Andric 65*81ad6265SDimitry Andric /// Returns true if and only if `Val1` is equivalent to `Val2`. 66*81ad6265SDimitry Andric static bool equivalentValues(QualType Type, Value *Val1, 67*81ad6265SDimitry Andric const Environment &Env1, Value *Val2, 68*81ad6265SDimitry Andric const Environment &Env2, 69*81ad6265SDimitry Andric Environment::ValueModel &Model) { 70*81ad6265SDimitry Andric return Val1 == Val2 || areEquivalentIndirectionValues(Val1, Val2) || 71*81ad6265SDimitry Andric Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2); 72*81ad6265SDimitry Andric } 73*81ad6265SDimitry Andric 74*81ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, 75*81ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single 76*81ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 77*81ad6265SDimitry Andric /// meaning depends on `Model`. 78*81ad6265SDimitry Andric static Value *mergeDistinctValues(QualType Type, Value *Val1, 79*81ad6265SDimitry Andric const Environment &Env1, Value *Val2, 80*81ad6265SDimitry Andric const Environment &Env2, 81*81ad6265SDimitry Andric Environment &MergedEnv, 82*81ad6265SDimitry Andric Environment::ValueModel &Model) { 83*81ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 84*81ad6265SDimitry Andric // in the respective path conditions. 85*81ad6265SDimitry Andric // 86*81ad6265SDimitry Andric // FIXME: Does not work for backedges, since the two (or more) paths will not 87*81ad6265SDimitry Andric // have mutually exclusive conditions. 88*81ad6265SDimitry Andric if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) { 89*81ad6265SDimitry Andric auto *Expr2 = cast<BoolValue>(Val2); 90*81ad6265SDimitry Andric auto &MergedVal = MergedEnv.makeAtomicBoolValue(); 91*81ad6265SDimitry Andric MergedEnv.addToFlowCondition(MergedEnv.makeOr( 92*81ad6265SDimitry Andric MergedEnv.makeAnd(Env1.getFlowConditionToken(), 93*81ad6265SDimitry Andric MergedEnv.makeIff(MergedVal, *Expr1)), 94*81ad6265SDimitry Andric MergedEnv.makeAnd(Env2.getFlowConditionToken(), 95*81ad6265SDimitry Andric MergedEnv.makeIff(MergedVal, *Expr2)))); 96*81ad6265SDimitry Andric return &MergedVal; 97*81ad6265SDimitry Andric } 98*81ad6265SDimitry Andric 99*81ad6265SDimitry Andric // FIXME: add unit tests that cover this statement. 100*81ad6265SDimitry Andric if (areEquivalentIndirectionValues(Val1, Val2)) { 101*81ad6265SDimitry Andric return Val1; 102*81ad6265SDimitry Andric } 103*81ad6265SDimitry Andric 104*81ad6265SDimitry Andric // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` 105*81ad6265SDimitry Andric // returns false to avoid storing unneeded values in `DACtx`. 106*81ad6265SDimitry Andric if (Value *MergedVal = MergedEnv.createValue(Type)) 107*81ad6265SDimitry Andric if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, MergedEnv)) 108*81ad6265SDimitry Andric return MergedVal; 109*81ad6265SDimitry Andric 110*81ad6265SDimitry Andric return nullptr; 111*81ad6265SDimitry Andric } 112*81ad6265SDimitry Andric 113*81ad6265SDimitry Andric /// Initializes a global storage value. 114*81ad6265SDimitry Andric static void initGlobalVar(const VarDecl &D, Environment &Env) { 115*81ad6265SDimitry Andric if (!D.hasGlobalStorage() || 116*81ad6265SDimitry Andric Env.getStorageLocation(D, SkipPast::None) != nullptr) 117*81ad6265SDimitry Andric return; 118*81ad6265SDimitry Andric 119*81ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(D); 120*81ad6265SDimitry Andric Env.setStorageLocation(D, Loc); 121*81ad6265SDimitry Andric if (auto *Val = Env.createValue(D.getType())) 122*81ad6265SDimitry Andric Env.setValue(Loc, *Val); 123*81ad6265SDimitry Andric } 124*81ad6265SDimitry Andric 125*81ad6265SDimitry Andric /// Initializes a global storage value. 126*81ad6265SDimitry Andric static void initGlobalVar(const Decl &D, Environment &Env) { 127*81ad6265SDimitry Andric if (auto *V = dyn_cast<VarDecl>(&D)) 128*81ad6265SDimitry Andric initGlobalVar(*V, Env); 129*81ad6265SDimitry Andric } 130*81ad6265SDimitry Andric 131*81ad6265SDimitry Andric /// Initializes global storage values that are declared or referenced from 132*81ad6265SDimitry Andric /// sub-statements of `S`. 133*81ad6265SDimitry Andric // FIXME: Add support for resetting globals after function calls to enable 134*81ad6265SDimitry Andric // the implementation of sound analyses. 135*81ad6265SDimitry Andric static void initGlobalVars(const Stmt &S, Environment &Env) { 136*81ad6265SDimitry Andric for (auto *Child : S.children()) { 137*81ad6265SDimitry Andric if (Child != nullptr) 138*81ad6265SDimitry Andric initGlobalVars(*Child, Env); 139*81ad6265SDimitry Andric } 140*81ad6265SDimitry Andric 141*81ad6265SDimitry Andric if (auto *DS = dyn_cast<DeclStmt>(&S)) { 142*81ad6265SDimitry Andric if (DS->isSingleDecl()) { 143*81ad6265SDimitry Andric initGlobalVar(*DS->getSingleDecl(), Env); 144*81ad6265SDimitry Andric } else { 145*81ad6265SDimitry Andric for (auto *D : DS->getDeclGroup()) 146*81ad6265SDimitry Andric initGlobalVar(*D, Env); 147*81ad6265SDimitry Andric } 148*81ad6265SDimitry Andric } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 149*81ad6265SDimitry Andric initGlobalVar(*E->getDecl(), Env); 150*81ad6265SDimitry Andric } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 151*81ad6265SDimitry Andric initGlobalVar(*E->getMemberDecl(), Env); 152*81ad6265SDimitry Andric } 153*81ad6265SDimitry Andric } 154*81ad6265SDimitry Andric 155*81ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx) 156*81ad6265SDimitry Andric : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {} 157*81ad6265SDimitry Andric 158*81ad6265SDimitry Andric Environment::Environment(const Environment &Other) 159*81ad6265SDimitry Andric : DACtx(Other.DACtx), DeclToLoc(Other.DeclToLoc), 160*81ad6265SDimitry Andric ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal), 161*81ad6265SDimitry Andric MemberLocToStruct(Other.MemberLocToStruct), 162*81ad6265SDimitry Andric FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) { 163*81ad6265SDimitry Andric } 164*81ad6265SDimitry Andric 165*81ad6265SDimitry Andric Environment &Environment::operator=(const Environment &Other) { 166*81ad6265SDimitry Andric Environment Copy(Other); 167*81ad6265SDimitry Andric *this = std::move(Copy); 168*81ad6265SDimitry Andric return *this; 1691fd87a68SDimitry Andric } 1701fd87a68SDimitry Andric 17104eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx, 17204eeddc0SDimitry Andric const DeclContext &DeclCtx) 17304eeddc0SDimitry Andric : Environment(DACtx) { 17404eeddc0SDimitry Andric if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) { 175*81ad6265SDimitry Andric assert(FuncDecl->getBody() != nullptr); 176*81ad6265SDimitry Andric initGlobalVars(*FuncDecl->getBody(), *this); 17704eeddc0SDimitry Andric for (const auto *ParamDecl : FuncDecl->parameters()) { 17804eeddc0SDimitry Andric assert(ParamDecl != nullptr); 17904eeddc0SDimitry Andric auto &ParamLoc = createStorageLocation(*ParamDecl); 18004eeddc0SDimitry Andric setStorageLocation(*ParamDecl, ParamLoc); 18104eeddc0SDimitry Andric if (Value *ParamVal = createValue(ParamDecl->getType())) 18204eeddc0SDimitry Andric setValue(ParamLoc, *ParamVal); 18304eeddc0SDimitry Andric } 18404eeddc0SDimitry Andric } 18504eeddc0SDimitry Andric 18604eeddc0SDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) { 187*81ad6265SDimitry Andric auto *Parent = MethodDecl->getParent(); 188*81ad6265SDimitry Andric assert(Parent != nullptr); 189*81ad6265SDimitry Andric if (Parent->isLambda()) 190*81ad6265SDimitry Andric MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext()); 191*81ad6265SDimitry Andric 192*81ad6265SDimitry Andric if (MethodDecl && !MethodDecl->isStatic()) { 19304eeddc0SDimitry Andric QualType ThisPointeeType = MethodDecl->getThisObjectType(); 19404eeddc0SDimitry Andric // FIXME: Add support for union types. 19504eeddc0SDimitry Andric if (!ThisPointeeType->isUnionType()) { 19604eeddc0SDimitry Andric auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType); 19704eeddc0SDimitry Andric DACtx.setThisPointeeStorageLocation(ThisPointeeLoc); 19804eeddc0SDimitry Andric if (Value *ThisPointeeVal = createValue(ThisPointeeType)) 19904eeddc0SDimitry Andric setValue(ThisPointeeLoc, *ThisPointeeVal); 20004eeddc0SDimitry Andric } 20104eeddc0SDimitry Andric } 20204eeddc0SDimitry Andric } 20304eeddc0SDimitry Andric } 20404eeddc0SDimitry Andric 2051fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 2061fd87a68SDimitry Andric Environment::ValueModel &Model) const { 20704eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 2081fd87a68SDimitry Andric 2091fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 2101fd87a68SDimitry Andric return false; 2111fd87a68SDimitry Andric 2121fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 2131fd87a68SDimitry Andric return false; 2141fd87a68SDimitry Andric 215*81ad6265SDimitry Andric // Compare the contents for the intersection of their domains. 2161fd87a68SDimitry Andric for (auto &Entry : LocToVal) { 2171fd87a68SDimitry Andric const StorageLocation *Loc = Entry.first; 2181fd87a68SDimitry Andric assert(Loc != nullptr); 2191fd87a68SDimitry Andric 2201fd87a68SDimitry Andric Value *Val = Entry.second; 2211fd87a68SDimitry Andric assert(Val != nullptr); 2221fd87a68SDimitry Andric 2231fd87a68SDimitry Andric auto It = Other.LocToVal.find(Loc); 2241fd87a68SDimitry Andric if (It == Other.LocToVal.end()) 225*81ad6265SDimitry Andric continue; 2261fd87a68SDimitry Andric assert(It->second != nullptr); 2271fd87a68SDimitry Andric 228*81ad6265SDimitry Andric if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model)) 2291fd87a68SDimitry Andric return false; 2301fd87a68SDimitry Andric } 2311fd87a68SDimitry Andric 2321fd87a68SDimitry Andric return true; 23304eeddc0SDimitry Andric } 23404eeddc0SDimitry Andric 23504eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other, 2361fd87a68SDimitry Andric Environment::ValueModel &Model) { 23704eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 23804eeddc0SDimitry Andric 23904eeddc0SDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 24004eeddc0SDimitry Andric 241*81ad6265SDimitry Andric Environment JoinedEnv(*DACtx); 242*81ad6265SDimitry Andric 243*81ad6265SDimitry Andric JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 244*81ad6265SDimitry Andric if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size()) 24504eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 24604eeddc0SDimitry Andric 247*81ad6265SDimitry Andric JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc); 248*81ad6265SDimitry Andric if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size()) 24904eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 25004eeddc0SDimitry Andric 251*81ad6265SDimitry Andric JoinedEnv.MemberLocToStruct = 252*81ad6265SDimitry Andric intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct); 253*81ad6265SDimitry Andric if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size()) 254*81ad6265SDimitry Andric Effect = LatticeJoinEffect::Changed; 255*81ad6265SDimitry Andric 256*81ad6265SDimitry Andric // FIXME: set `Effect` as needed. 257*81ad6265SDimitry Andric JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions( 258*81ad6265SDimitry Andric *FlowConditionToken, *Other.FlowConditionToken); 259*81ad6265SDimitry Andric 260*81ad6265SDimitry Andric for (auto &Entry : LocToVal) { 26104eeddc0SDimitry Andric const StorageLocation *Loc = Entry.first; 26204eeddc0SDimitry Andric assert(Loc != nullptr); 26304eeddc0SDimitry Andric 26404eeddc0SDimitry Andric Value *Val = Entry.second; 26504eeddc0SDimitry Andric assert(Val != nullptr); 26604eeddc0SDimitry Andric 26704eeddc0SDimitry Andric auto It = Other.LocToVal.find(Loc); 26804eeddc0SDimitry Andric if (It == Other.LocToVal.end()) 26904eeddc0SDimitry Andric continue; 27004eeddc0SDimitry Andric assert(It->second != nullptr); 27104eeddc0SDimitry Andric 272*81ad6265SDimitry Andric if (Val == It->second) { 273*81ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, Val}); 27404eeddc0SDimitry Andric continue; 27504eeddc0SDimitry Andric } 27604eeddc0SDimitry Andric 277*81ad6265SDimitry Andric if (Value *MergedVal = mergeDistinctValues( 278*81ad6265SDimitry Andric Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model)) 279*81ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, MergedVal}); 28004eeddc0SDimitry Andric } 281*81ad6265SDimitry Andric if (LocToVal.size() != JoinedEnv.LocToVal.size()) 28204eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 28304eeddc0SDimitry Andric 284*81ad6265SDimitry Andric *this = std::move(JoinedEnv); 285*81ad6265SDimitry Andric 28604eeddc0SDimitry Andric return Effect; 28704eeddc0SDimitry Andric } 28804eeddc0SDimitry Andric 28904eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 290*81ad6265SDimitry Andric return DACtx->getStableStorageLocation(Type); 29104eeddc0SDimitry Andric } 29204eeddc0SDimitry Andric 29304eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 29404eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 29504eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 29604eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 297*81ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 29804eeddc0SDimitry Andric } 29904eeddc0SDimitry Andric 30004eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 30104eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 30204eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 30304eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 304*81ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 30504eeddc0SDimitry Andric } 30604eeddc0SDimitry Andric 30704eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 30804eeddc0SDimitry Andric assert(DeclToLoc.find(&D) == DeclToLoc.end()); 30904eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 31004eeddc0SDimitry Andric } 31104eeddc0SDimitry Andric 31204eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D, 31304eeddc0SDimitry Andric SkipPast SP) const { 31404eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 31504eeddc0SDimitry Andric return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); 31604eeddc0SDimitry Andric } 31704eeddc0SDimitry Andric 31804eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 319*81ad6265SDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 320*81ad6265SDimitry Andric assert(ExprToLoc.find(&CanonE) == ExprToLoc.end()); 321*81ad6265SDimitry Andric ExprToLoc[&CanonE] = &Loc; 32204eeddc0SDimitry Andric } 32304eeddc0SDimitry Andric 32404eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E, 32504eeddc0SDimitry Andric SkipPast SP) const { 326*81ad6265SDimitry Andric // FIXME: Add a test with parens. 327*81ad6265SDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 32804eeddc0SDimitry Andric return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 32904eeddc0SDimitry Andric } 33004eeddc0SDimitry Andric 33104eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const { 33204eeddc0SDimitry Andric return DACtx->getThisPointeeStorageLocation(); 33304eeddc0SDimitry Andric } 33404eeddc0SDimitry Andric 335*81ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 336*81ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 337*81ad6265SDimitry Andric } 338*81ad6265SDimitry Andric 33904eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 34004eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 34104eeddc0SDimitry Andric 34204eeddc0SDimitry Andric if (auto *StructVal = dyn_cast<StructValue>(&Val)) { 34304eeddc0SDimitry Andric auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc); 34404eeddc0SDimitry Andric 34504eeddc0SDimitry Andric const QualType Type = AggregateLoc.getType(); 34604eeddc0SDimitry Andric assert(Type->isStructureOrClassType()); 34704eeddc0SDimitry Andric 348*81ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 34904eeddc0SDimitry Andric assert(Field != nullptr); 350*81ad6265SDimitry Andric StorageLocation &FieldLoc = AggregateLoc.getChild(*Field); 351*81ad6265SDimitry Andric MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field); 352*81ad6265SDimitry Andric if (auto *FieldVal = StructVal->getChild(*Field)) 353*81ad6265SDimitry Andric setValue(FieldLoc, *FieldVal); 35404eeddc0SDimitry Andric } 35504eeddc0SDimitry Andric } 356*81ad6265SDimitry Andric 357*81ad6265SDimitry Andric auto IT = MemberLocToStruct.find(&Loc); 358*81ad6265SDimitry Andric if (IT != MemberLocToStruct.end()) { 359*81ad6265SDimitry Andric // `Loc` is the location of a struct member so we need to also update the 360*81ad6265SDimitry Andric // value of the member in the corresponding `StructValue`. 361*81ad6265SDimitry Andric 362*81ad6265SDimitry Andric assert(IT->second.first != nullptr); 363*81ad6265SDimitry Andric StructValue &StructVal = *IT->second.first; 364*81ad6265SDimitry Andric 365*81ad6265SDimitry Andric assert(IT->second.second != nullptr); 366*81ad6265SDimitry Andric const ValueDecl &Member = *IT->second.second; 367*81ad6265SDimitry Andric 368*81ad6265SDimitry Andric StructVal.setChild(Member, Val); 369*81ad6265SDimitry Andric } 37004eeddc0SDimitry Andric } 37104eeddc0SDimitry Andric 37204eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 37304eeddc0SDimitry Andric auto It = LocToVal.find(&Loc); 37404eeddc0SDimitry Andric return It == LocToVal.end() ? nullptr : It->second; 37504eeddc0SDimitry Andric } 37604eeddc0SDimitry Andric 37704eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { 37804eeddc0SDimitry Andric auto *Loc = getStorageLocation(D, SP); 37904eeddc0SDimitry Andric if (Loc == nullptr) 38004eeddc0SDimitry Andric return nullptr; 38104eeddc0SDimitry Andric return getValue(*Loc); 38204eeddc0SDimitry Andric } 38304eeddc0SDimitry Andric 38404eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const { 38504eeddc0SDimitry Andric auto *Loc = getStorageLocation(E, SP); 38604eeddc0SDimitry Andric if (Loc == nullptr) 38704eeddc0SDimitry Andric return nullptr; 38804eeddc0SDimitry Andric return getValue(*Loc); 38904eeddc0SDimitry Andric } 39004eeddc0SDimitry Andric 39104eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 39204eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 393*81ad6265SDimitry Andric int CreatedValuesCount = 0; 394*81ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 395*81ad6265SDimitry Andric CreatedValuesCount); 396*81ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 397*81ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 398*81ad6265SDimitry Andric << '\n'; 399*81ad6265SDimitry Andric } 400*81ad6265SDimitry Andric return Val; 40104eeddc0SDimitry Andric } 40204eeddc0SDimitry Andric 40304eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 404*81ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 405*81ad6265SDimitry Andric int &CreatedValuesCount) { 40604eeddc0SDimitry Andric assert(!Type.isNull()); 40704eeddc0SDimitry Andric 408*81ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 409*81ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 410*81ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 411*81ad6265SDimitry Andric return nullptr; 412*81ad6265SDimitry Andric 413*81ad6265SDimitry Andric if (Type->isBooleanType()) { 414*81ad6265SDimitry Andric CreatedValuesCount++; 415*81ad6265SDimitry Andric return &makeAtomicBoolValue(); 416*81ad6265SDimitry Andric } 417*81ad6265SDimitry Andric 41804eeddc0SDimitry Andric if (Type->isIntegerType()) { 419*81ad6265SDimitry Andric CreatedValuesCount++; 42004eeddc0SDimitry Andric return &takeOwnership(std::make_unique<IntegerValue>()); 42104eeddc0SDimitry Andric } 42204eeddc0SDimitry Andric 42304eeddc0SDimitry Andric if (Type->isReferenceType()) { 424*81ad6265SDimitry Andric CreatedValuesCount++; 425*81ad6265SDimitry Andric QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType(); 42604eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 42704eeddc0SDimitry Andric 428*81ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 429*81ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 430*81ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 43104eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 43204eeddc0SDimitry Andric 43304eeddc0SDimitry Andric if (PointeeVal != nullptr) 43404eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 43504eeddc0SDimitry Andric } 43604eeddc0SDimitry Andric 43704eeddc0SDimitry Andric return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 43804eeddc0SDimitry Andric } 43904eeddc0SDimitry Andric 44004eeddc0SDimitry Andric if (Type->isPointerType()) { 441*81ad6265SDimitry Andric CreatedValuesCount++; 442*81ad6265SDimitry Andric QualType PointeeType = Type->castAs<PointerType>()->getPointeeType(); 44304eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 44404eeddc0SDimitry Andric 445*81ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 446*81ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 447*81ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 44804eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 44904eeddc0SDimitry Andric 45004eeddc0SDimitry Andric if (PointeeVal != nullptr) 45104eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 45204eeddc0SDimitry Andric } 45304eeddc0SDimitry Andric 45404eeddc0SDimitry Andric return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 45504eeddc0SDimitry Andric } 45604eeddc0SDimitry Andric 45704eeddc0SDimitry Andric if (Type->isStructureOrClassType()) { 458*81ad6265SDimitry Andric CreatedValuesCount++; 45904eeddc0SDimitry Andric // FIXME: Initialize only fields that are accessed in the context that is 46004eeddc0SDimitry Andric // being analyzed. 46104eeddc0SDimitry Andric llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 462*81ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 46304eeddc0SDimitry Andric assert(Field != nullptr); 46404eeddc0SDimitry Andric 46504eeddc0SDimitry Andric QualType FieldType = Field->getType(); 46604eeddc0SDimitry Andric if (Visited.contains(FieldType.getCanonicalType())) 46704eeddc0SDimitry Andric continue; 46804eeddc0SDimitry Andric 46904eeddc0SDimitry Andric Visited.insert(FieldType.getCanonicalType()); 470*81ad6265SDimitry Andric if (auto *FieldValue = createValueUnlessSelfReferential( 471*81ad6265SDimitry Andric FieldType, Visited, Depth + 1, CreatedValuesCount)) 472*81ad6265SDimitry Andric FieldValues.insert({Field, FieldValue}); 47304eeddc0SDimitry Andric Visited.erase(FieldType.getCanonicalType()); 47404eeddc0SDimitry Andric } 47504eeddc0SDimitry Andric 47604eeddc0SDimitry Andric return &takeOwnership( 47704eeddc0SDimitry Andric std::make_unique<StructValue>(std::move(FieldValues))); 47804eeddc0SDimitry Andric } 47904eeddc0SDimitry Andric 48004eeddc0SDimitry Andric return nullptr; 48104eeddc0SDimitry Andric } 48204eeddc0SDimitry Andric 48304eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 48404eeddc0SDimitry Andric switch (SP) { 48504eeddc0SDimitry Andric case SkipPast::None: 48604eeddc0SDimitry Andric return Loc; 48704eeddc0SDimitry Andric case SkipPast::Reference: 48804eeddc0SDimitry Andric // References cannot be chained so we only need to skip past one level of 48904eeddc0SDimitry Andric // indirection. 49004eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 491*81ad6265SDimitry Andric return Val->getReferentLoc(); 49204eeddc0SDimitry Andric return Loc; 49304eeddc0SDimitry Andric case SkipPast::ReferenceThenPointer: 49404eeddc0SDimitry Andric StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); 49504eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef))) 49604eeddc0SDimitry Andric return Val->getPointeeLoc(); 49704eeddc0SDimitry Andric return LocPastRef; 49804eeddc0SDimitry Andric } 49904eeddc0SDimitry Andric llvm_unreachable("bad SkipPast kind"); 50004eeddc0SDimitry Andric } 50104eeddc0SDimitry Andric 50204eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc, 50304eeddc0SDimitry Andric SkipPast SP) const { 50404eeddc0SDimitry Andric return skip(*const_cast<StorageLocation *>(&Loc), SP); 50504eeddc0SDimitry Andric } 50604eeddc0SDimitry Andric 507*81ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) { 508*81ad6265SDimitry Andric DACtx->addFlowConditionConstraint(*FlowConditionToken, Val); 509*81ad6265SDimitry Andric } 510*81ad6265SDimitry Andric 511*81ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const { 512*81ad6265SDimitry Andric return DACtx->flowConditionImplies(*FlowConditionToken, Val); 513*81ad6265SDimitry Andric } 514*81ad6265SDimitry Andric 51504eeddc0SDimitry Andric } // namespace dataflow 51604eeddc0SDimitry Andric } // namespace clang 517