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" 1804eeddc0SDimitry Andric #include "clang/AST/Type.h" 1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2104eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 2204eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 2381ad6265SDimitry Andric #include "llvm/Support/Casting.h" 2404eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2581ad6265SDimitry Andric #include <cassert> 2604eeddc0SDimitry Andric #include <memory> 2704eeddc0SDimitry Andric #include <utility> 2804eeddc0SDimitry Andric 2904eeddc0SDimitry Andric namespace clang { 3004eeddc0SDimitry Andric namespace dataflow { 3104eeddc0SDimitry Andric 3281ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 3381ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 3481ad6265SDimitry Andric // analysis. 3581ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 3681ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 3781ad6265SDimitry Andric 3804eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 3904eeddc0SDimitry Andric template <typename K, typename V> 4004eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 4104eeddc0SDimitry Andric const llvm::DenseMap<K, V> &Map2) { 4204eeddc0SDimitry Andric llvm::DenseMap<K, V> Result; 4304eeddc0SDimitry Andric for (auto &Entry : Map1) { 4404eeddc0SDimitry Andric auto It = Map2.find(Entry.first); 4504eeddc0SDimitry Andric if (It != Map2.end() && Entry.second == It->second) 4604eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 4704eeddc0SDimitry Andric } 4804eeddc0SDimitry Andric return Result; 4904eeddc0SDimitry Andric } 5004eeddc0SDimitry Andric 5181ad6265SDimitry Andric static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) { 5281ad6265SDimitry Andric if (auto *IndVal1 = dyn_cast<ReferenceValue>(Val1)) { 5381ad6265SDimitry Andric auto *IndVal2 = cast<ReferenceValue>(Val2); 5481ad6265SDimitry Andric return &IndVal1->getReferentLoc() == &IndVal2->getReferentLoc(); 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric if (auto *IndVal1 = dyn_cast<PointerValue>(Val1)) { 5781ad6265SDimitry Andric auto *IndVal2 = cast<PointerValue>(Val2); 581fd87a68SDimitry Andric return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); 591fd87a68SDimitry Andric } 6081ad6265SDimitry Andric return false; 6181ad6265SDimitry Andric } 621fd87a68SDimitry Andric 6381ad6265SDimitry Andric /// Returns true if and only if `Val1` is equivalent to `Val2`. 6481ad6265SDimitry Andric static bool equivalentValues(QualType Type, Value *Val1, 6581ad6265SDimitry Andric const Environment &Env1, Value *Val2, 6681ad6265SDimitry Andric const Environment &Env2, 6781ad6265SDimitry Andric Environment::ValueModel &Model) { 6881ad6265SDimitry Andric return Val1 == Val2 || areEquivalentIndirectionValues(Val1, Val2) || 6981ad6265SDimitry Andric Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2); 7081ad6265SDimitry Andric } 7181ad6265SDimitry Andric 7281ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, 7381ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single 7481ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 7581ad6265SDimitry Andric /// meaning depends on `Model`. 7681ad6265SDimitry Andric static Value *mergeDistinctValues(QualType Type, Value *Val1, 7781ad6265SDimitry Andric const Environment &Env1, Value *Val2, 7881ad6265SDimitry Andric const Environment &Env2, 7981ad6265SDimitry Andric Environment &MergedEnv, 8081ad6265SDimitry Andric Environment::ValueModel &Model) { 8181ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 8281ad6265SDimitry Andric // in the respective path conditions. 8381ad6265SDimitry Andric // 8481ad6265SDimitry Andric // FIXME: Does not work for backedges, since the two (or more) paths will not 8581ad6265SDimitry Andric // have mutually exclusive conditions. 8681ad6265SDimitry Andric if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) { 8781ad6265SDimitry Andric auto *Expr2 = cast<BoolValue>(Val2); 8881ad6265SDimitry Andric auto &MergedVal = MergedEnv.makeAtomicBoolValue(); 8981ad6265SDimitry Andric MergedEnv.addToFlowCondition(MergedEnv.makeOr( 9081ad6265SDimitry Andric MergedEnv.makeAnd(Env1.getFlowConditionToken(), 9181ad6265SDimitry Andric MergedEnv.makeIff(MergedVal, *Expr1)), 9281ad6265SDimitry Andric MergedEnv.makeAnd(Env2.getFlowConditionToken(), 9381ad6265SDimitry Andric MergedEnv.makeIff(MergedVal, *Expr2)))); 9481ad6265SDimitry Andric return &MergedVal; 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric // FIXME: add unit tests that cover this statement. 9881ad6265SDimitry Andric if (areEquivalentIndirectionValues(Val1, Val2)) { 9981ad6265SDimitry Andric return Val1; 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` 10381ad6265SDimitry Andric // returns false to avoid storing unneeded values in `DACtx`. 10481ad6265SDimitry Andric if (Value *MergedVal = MergedEnv.createValue(Type)) 10581ad6265SDimitry Andric if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, MergedEnv)) 10681ad6265SDimitry Andric return MergedVal; 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric return nullptr; 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric /// Initializes a global storage value. 11281ad6265SDimitry Andric static void initGlobalVar(const VarDecl &D, Environment &Env) { 11381ad6265SDimitry Andric if (!D.hasGlobalStorage() || 11481ad6265SDimitry Andric Env.getStorageLocation(D, SkipPast::None) != nullptr) 11581ad6265SDimitry Andric return; 11681ad6265SDimitry Andric 11781ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(D); 11881ad6265SDimitry Andric Env.setStorageLocation(D, Loc); 11981ad6265SDimitry Andric if (auto *Val = Env.createValue(D.getType())) 12081ad6265SDimitry Andric Env.setValue(Loc, *Val); 12181ad6265SDimitry Andric } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric /// Initializes a global storage value. 12481ad6265SDimitry Andric static void initGlobalVar(const Decl &D, Environment &Env) { 12581ad6265SDimitry Andric if (auto *V = dyn_cast<VarDecl>(&D)) 12681ad6265SDimitry Andric initGlobalVar(*V, Env); 12781ad6265SDimitry Andric } 12881ad6265SDimitry Andric 12981ad6265SDimitry Andric /// Initializes global storage values that are declared or referenced from 13081ad6265SDimitry Andric /// sub-statements of `S`. 13181ad6265SDimitry Andric // FIXME: Add support for resetting globals after function calls to enable 13281ad6265SDimitry Andric // the implementation of sound analyses. 13381ad6265SDimitry Andric static void initGlobalVars(const Stmt &S, Environment &Env) { 13481ad6265SDimitry Andric for (auto *Child : S.children()) { 13581ad6265SDimitry Andric if (Child != nullptr) 13681ad6265SDimitry Andric initGlobalVars(*Child, Env); 13781ad6265SDimitry Andric } 13881ad6265SDimitry Andric 13981ad6265SDimitry Andric if (auto *DS = dyn_cast<DeclStmt>(&S)) { 14081ad6265SDimitry Andric if (DS->isSingleDecl()) { 14181ad6265SDimitry Andric initGlobalVar(*DS->getSingleDecl(), Env); 14281ad6265SDimitry Andric } else { 14381ad6265SDimitry Andric for (auto *D : DS->getDeclGroup()) 14481ad6265SDimitry Andric initGlobalVar(*D, Env); 14581ad6265SDimitry Andric } 14681ad6265SDimitry Andric } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 14781ad6265SDimitry Andric initGlobalVar(*E->getDecl(), Env); 14881ad6265SDimitry Andric } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 14981ad6265SDimitry Andric initGlobalVar(*E->getMemberDecl(), Env); 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx) 15481ad6265SDimitry Andric : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {} 15581ad6265SDimitry Andric 15681ad6265SDimitry Andric Environment::Environment(const Environment &Other) 15781ad6265SDimitry Andric : DACtx(Other.DACtx), DeclToLoc(Other.DeclToLoc), 15881ad6265SDimitry Andric ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal), 15981ad6265SDimitry Andric MemberLocToStruct(Other.MemberLocToStruct), 16081ad6265SDimitry Andric FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) { 16181ad6265SDimitry Andric } 16281ad6265SDimitry Andric 16381ad6265SDimitry Andric Environment &Environment::operator=(const Environment &Other) { 16481ad6265SDimitry Andric Environment Copy(Other); 16581ad6265SDimitry Andric *this = std::move(Copy); 16681ad6265SDimitry Andric return *this; 1671fd87a68SDimitry Andric } 1681fd87a68SDimitry Andric 16904eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx, 17004eeddc0SDimitry Andric const DeclContext &DeclCtx) 17104eeddc0SDimitry Andric : Environment(DACtx) { 17204eeddc0SDimitry Andric if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) { 17381ad6265SDimitry Andric assert(FuncDecl->getBody() != nullptr); 17481ad6265SDimitry Andric initGlobalVars(*FuncDecl->getBody(), *this); 17504eeddc0SDimitry Andric for (const auto *ParamDecl : FuncDecl->parameters()) { 17604eeddc0SDimitry Andric assert(ParamDecl != nullptr); 17704eeddc0SDimitry Andric auto &ParamLoc = createStorageLocation(*ParamDecl); 17804eeddc0SDimitry Andric setStorageLocation(*ParamDecl, ParamLoc); 17904eeddc0SDimitry Andric if (Value *ParamVal = createValue(ParamDecl->getType())) 18004eeddc0SDimitry Andric setValue(ParamLoc, *ParamVal); 18104eeddc0SDimitry Andric } 18204eeddc0SDimitry Andric } 18304eeddc0SDimitry Andric 18404eeddc0SDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) { 18581ad6265SDimitry Andric auto *Parent = MethodDecl->getParent(); 18681ad6265SDimitry Andric assert(Parent != nullptr); 18781ad6265SDimitry Andric if (Parent->isLambda()) 18881ad6265SDimitry Andric MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext()); 18981ad6265SDimitry Andric 19081ad6265SDimitry Andric if (MethodDecl && !MethodDecl->isStatic()) { 19104eeddc0SDimitry Andric QualType ThisPointeeType = MethodDecl->getThisObjectType(); 19204eeddc0SDimitry Andric // FIXME: Add support for union types. 19304eeddc0SDimitry Andric if (!ThisPointeeType->isUnionType()) { 19404eeddc0SDimitry Andric auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType); 19504eeddc0SDimitry Andric DACtx.setThisPointeeStorageLocation(ThisPointeeLoc); 19604eeddc0SDimitry Andric if (Value *ThisPointeeVal = createValue(ThisPointeeType)) 19704eeddc0SDimitry Andric setValue(ThisPointeeLoc, *ThisPointeeVal); 19804eeddc0SDimitry Andric } 19904eeddc0SDimitry Andric } 20004eeddc0SDimitry Andric } 20104eeddc0SDimitry Andric } 20204eeddc0SDimitry Andric 2031fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 2041fd87a68SDimitry Andric Environment::ValueModel &Model) const { 20504eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 2061fd87a68SDimitry Andric 2071fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 2081fd87a68SDimitry Andric return false; 2091fd87a68SDimitry Andric 2101fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 2111fd87a68SDimitry Andric return false; 2121fd87a68SDimitry Andric 21381ad6265SDimitry Andric // Compare the contents for the intersection of their domains. 2141fd87a68SDimitry Andric for (auto &Entry : LocToVal) { 2151fd87a68SDimitry Andric const StorageLocation *Loc = Entry.first; 2161fd87a68SDimitry Andric assert(Loc != nullptr); 2171fd87a68SDimitry Andric 2181fd87a68SDimitry Andric Value *Val = Entry.second; 2191fd87a68SDimitry Andric assert(Val != nullptr); 2201fd87a68SDimitry Andric 2211fd87a68SDimitry Andric auto It = Other.LocToVal.find(Loc); 2221fd87a68SDimitry Andric if (It == Other.LocToVal.end()) 22381ad6265SDimitry Andric continue; 2241fd87a68SDimitry Andric assert(It->second != nullptr); 2251fd87a68SDimitry Andric 22681ad6265SDimitry Andric if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model)) 2271fd87a68SDimitry Andric return false; 2281fd87a68SDimitry Andric } 2291fd87a68SDimitry Andric 2301fd87a68SDimitry Andric return true; 23104eeddc0SDimitry Andric } 23204eeddc0SDimitry Andric 23304eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other, 2341fd87a68SDimitry Andric Environment::ValueModel &Model) { 23504eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 23604eeddc0SDimitry Andric 23704eeddc0SDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 23804eeddc0SDimitry Andric 23981ad6265SDimitry Andric Environment JoinedEnv(*DACtx); 24081ad6265SDimitry Andric 24181ad6265SDimitry Andric JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 24281ad6265SDimitry Andric if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size()) 24304eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 24404eeddc0SDimitry Andric 24581ad6265SDimitry Andric JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc); 24681ad6265SDimitry Andric if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size()) 24704eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 24804eeddc0SDimitry Andric 24981ad6265SDimitry Andric JoinedEnv.MemberLocToStruct = 25081ad6265SDimitry Andric intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct); 25181ad6265SDimitry Andric if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size()) 25281ad6265SDimitry Andric Effect = LatticeJoinEffect::Changed; 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric // FIXME: set `Effect` as needed. 25581ad6265SDimitry Andric JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions( 25681ad6265SDimitry Andric *FlowConditionToken, *Other.FlowConditionToken); 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric for (auto &Entry : LocToVal) { 25904eeddc0SDimitry Andric const StorageLocation *Loc = Entry.first; 26004eeddc0SDimitry Andric assert(Loc != nullptr); 26104eeddc0SDimitry Andric 26204eeddc0SDimitry Andric Value *Val = Entry.second; 26304eeddc0SDimitry Andric assert(Val != nullptr); 26404eeddc0SDimitry Andric 26504eeddc0SDimitry Andric auto It = Other.LocToVal.find(Loc); 26604eeddc0SDimitry Andric if (It == Other.LocToVal.end()) 26704eeddc0SDimitry Andric continue; 26804eeddc0SDimitry Andric assert(It->second != nullptr); 26904eeddc0SDimitry Andric 27081ad6265SDimitry Andric if (Val == It->second) { 27181ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, Val}); 27204eeddc0SDimitry Andric continue; 27304eeddc0SDimitry Andric } 27404eeddc0SDimitry Andric 27581ad6265SDimitry Andric if (Value *MergedVal = mergeDistinctValues( 27681ad6265SDimitry Andric Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model)) 27781ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, MergedVal}); 27804eeddc0SDimitry Andric } 27981ad6265SDimitry Andric if (LocToVal.size() != JoinedEnv.LocToVal.size()) 28004eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 28104eeddc0SDimitry Andric 28281ad6265SDimitry Andric *this = std::move(JoinedEnv); 28381ad6265SDimitry Andric 28404eeddc0SDimitry Andric return Effect; 28504eeddc0SDimitry Andric } 28604eeddc0SDimitry Andric 28704eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 28881ad6265SDimitry Andric return DACtx->getStableStorageLocation(Type); 28904eeddc0SDimitry Andric } 29004eeddc0SDimitry Andric 29104eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 29204eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 29304eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 29404eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 29581ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 29604eeddc0SDimitry Andric } 29704eeddc0SDimitry Andric 29804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 29904eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 30004eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 30104eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 30281ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 30304eeddc0SDimitry Andric } 30404eeddc0SDimitry Andric 30504eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 30604eeddc0SDimitry Andric assert(DeclToLoc.find(&D) == DeclToLoc.end()); 30704eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 30804eeddc0SDimitry Andric } 30904eeddc0SDimitry Andric 31004eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D, 31104eeddc0SDimitry Andric SkipPast SP) const { 31204eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 31304eeddc0SDimitry Andric return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); 31404eeddc0SDimitry Andric } 31504eeddc0SDimitry Andric 31604eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 31781ad6265SDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 31881ad6265SDimitry Andric assert(ExprToLoc.find(&CanonE) == ExprToLoc.end()); 31981ad6265SDimitry Andric ExprToLoc[&CanonE] = &Loc; 32004eeddc0SDimitry Andric } 32104eeddc0SDimitry Andric 32204eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E, 32304eeddc0SDimitry Andric SkipPast SP) const { 32481ad6265SDimitry Andric // FIXME: Add a test with parens. 32581ad6265SDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 32604eeddc0SDimitry Andric return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 32704eeddc0SDimitry Andric } 32804eeddc0SDimitry Andric 32904eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const { 33004eeddc0SDimitry Andric return DACtx->getThisPointeeStorageLocation(); 33104eeddc0SDimitry Andric } 33204eeddc0SDimitry Andric 33381ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 33481ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 33581ad6265SDimitry Andric } 33681ad6265SDimitry Andric 33704eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 33804eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 33904eeddc0SDimitry Andric 34004eeddc0SDimitry Andric if (auto *StructVal = dyn_cast<StructValue>(&Val)) { 34104eeddc0SDimitry Andric auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc); 34204eeddc0SDimitry Andric 34304eeddc0SDimitry Andric const QualType Type = AggregateLoc.getType(); 34404eeddc0SDimitry Andric assert(Type->isStructureOrClassType()); 34504eeddc0SDimitry Andric 34681ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 34704eeddc0SDimitry Andric assert(Field != nullptr); 34881ad6265SDimitry Andric StorageLocation &FieldLoc = AggregateLoc.getChild(*Field); 34981ad6265SDimitry Andric MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field); 35081ad6265SDimitry Andric if (auto *FieldVal = StructVal->getChild(*Field)) 35181ad6265SDimitry Andric setValue(FieldLoc, *FieldVal); 35204eeddc0SDimitry Andric } 35304eeddc0SDimitry Andric } 35481ad6265SDimitry Andric 35581ad6265SDimitry Andric auto IT = MemberLocToStruct.find(&Loc); 35681ad6265SDimitry Andric if (IT != MemberLocToStruct.end()) { 35781ad6265SDimitry Andric // `Loc` is the location of a struct member so we need to also update the 35881ad6265SDimitry Andric // value of the member in the corresponding `StructValue`. 35981ad6265SDimitry Andric 36081ad6265SDimitry Andric assert(IT->second.first != nullptr); 36181ad6265SDimitry Andric StructValue &StructVal = *IT->second.first; 36281ad6265SDimitry Andric 36381ad6265SDimitry Andric assert(IT->second.second != nullptr); 36481ad6265SDimitry Andric const ValueDecl &Member = *IT->second.second; 36581ad6265SDimitry Andric 36681ad6265SDimitry Andric StructVal.setChild(Member, Val); 36781ad6265SDimitry Andric } 36804eeddc0SDimitry Andric } 36904eeddc0SDimitry Andric 37004eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 37104eeddc0SDimitry Andric auto It = LocToVal.find(&Loc); 37204eeddc0SDimitry Andric return It == LocToVal.end() ? nullptr : It->second; 37304eeddc0SDimitry Andric } 37404eeddc0SDimitry Andric 37504eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { 37604eeddc0SDimitry Andric auto *Loc = getStorageLocation(D, SP); 37704eeddc0SDimitry Andric if (Loc == nullptr) 37804eeddc0SDimitry Andric return nullptr; 37904eeddc0SDimitry Andric return getValue(*Loc); 38004eeddc0SDimitry Andric } 38104eeddc0SDimitry Andric 38204eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const { 38304eeddc0SDimitry Andric auto *Loc = getStorageLocation(E, SP); 38404eeddc0SDimitry Andric if (Loc == nullptr) 38504eeddc0SDimitry Andric return nullptr; 38604eeddc0SDimitry Andric return getValue(*Loc); 38704eeddc0SDimitry Andric } 38804eeddc0SDimitry Andric 38904eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 39004eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 39181ad6265SDimitry Andric int CreatedValuesCount = 0; 39281ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 39381ad6265SDimitry Andric CreatedValuesCount); 39481ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 39581ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 39681ad6265SDimitry Andric << '\n'; 39781ad6265SDimitry Andric } 39881ad6265SDimitry Andric return Val; 39904eeddc0SDimitry Andric } 40004eeddc0SDimitry Andric 40104eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 40281ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 40381ad6265SDimitry Andric int &CreatedValuesCount) { 40404eeddc0SDimitry Andric assert(!Type.isNull()); 40504eeddc0SDimitry Andric 40681ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 40781ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 40881ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 40981ad6265SDimitry Andric return nullptr; 41081ad6265SDimitry Andric 41181ad6265SDimitry Andric if (Type->isBooleanType()) { 41281ad6265SDimitry Andric CreatedValuesCount++; 41381ad6265SDimitry Andric return &makeAtomicBoolValue(); 41481ad6265SDimitry Andric } 41581ad6265SDimitry Andric 41604eeddc0SDimitry Andric if (Type->isIntegerType()) { 41781ad6265SDimitry Andric CreatedValuesCount++; 41804eeddc0SDimitry Andric return &takeOwnership(std::make_unique<IntegerValue>()); 41904eeddc0SDimitry Andric } 42004eeddc0SDimitry Andric 42104eeddc0SDimitry Andric if (Type->isReferenceType()) { 42281ad6265SDimitry Andric CreatedValuesCount++; 42381ad6265SDimitry Andric QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType(); 42404eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 42504eeddc0SDimitry Andric 42681ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 42781ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 42881ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 42904eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 43004eeddc0SDimitry Andric 43104eeddc0SDimitry Andric if (PointeeVal != nullptr) 43204eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 43304eeddc0SDimitry Andric } 43404eeddc0SDimitry Andric 43504eeddc0SDimitry Andric return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 43604eeddc0SDimitry Andric } 43704eeddc0SDimitry Andric 43804eeddc0SDimitry Andric if (Type->isPointerType()) { 43981ad6265SDimitry Andric CreatedValuesCount++; 44081ad6265SDimitry Andric QualType PointeeType = Type->castAs<PointerType>()->getPointeeType(); 44104eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 44204eeddc0SDimitry Andric 44381ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 44481ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 44581ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 44604eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 44704eeddc0SDimitry Andric 44804eeddc0SDimitry Andric if (PointeeVal != nullptr) 44904eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 45004eeddc0SDimitry Andric } 45104eeddc0SDimitry Andric 45204eeddc0SDimitry Andric return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 45304eeddc0SDimitry Andric } 45404eeddc0SDimitry Andric 45504eeddc0SDimitry Andric if (Type->isStructureOrClassType()) { 45681ad6265SDimitry Andric CreatedValuesCount++; 45704eeddc0SDimitry Andric // FIXME: Initialize only fields that are accessed in the context that is 45804eeddc0SDimitry Andric // being analyzed. 45904eeddc0SDimitry Andric llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 46081ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 46104eeddc0SDimitry Andric assert(Field != nullptr); 46204eeddc0SDimitry Andric 46304eeddc0SDimitry Andric QualType FieldType = Field->getType(); 46404eeddc0SDimitry Andric if (Visited.contains(FieldType.getCanonicalType())) 46504eeddc0SDimitry Andric continue; 46604eeddc0SDimitry Andric 46704eeddc0SDimitry Andric Visited.insert(FieldType.getCanonicalType()); 46881ad6265SDimitry Andric if (auto *FieldValue = createValueUnlessSelfReferential( 46981ad6265SDimitry Andric FieldType, Visited, Depth + 1, CreatedValuesCount)) 47081ad6265SDimitry Andric FieldValues.insert({Field, FieldValue}); 47104eeddc0SDimitry Andric Visited.erase(FieldType.getCanonicalType()); 47204eeddc0SDimitry Andric } 47304eeddc0SDimitry Andric 47404eeddc0SDimitry Andric return &takeOwnership( 47504eeddc0SDimitry Andric std::make_unique<StructValue>(std::move(FieldValues))); 47604eeddc0SDimitry Andric } 47704eeddc0SDimitry Andric 47804eeddc0SDimitry Andric return nullptr; 47904eeddc0SDimitry Andric } 48004eeddc0SDimitry Andric 48104eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 48204eeddc0SDimitry Andric switch (SP) { 48304eeddc0SDimitry Andric case SkipPast::None: 48404eeddc0SDimitry Andric return Loc; 48504eeddc0SDimitry Andric case SkipPast::Reference: 48604eeddc0SDimitry Andric // References cannot be chained so we only need to skip past one level of 48704eeddc0SDimitry Andric // indirection. 48804eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 48981ad6265SDimitry Andric return Val->getReferentLoc(); 49004eeddc0SDimitry Andric return Loc; 49104eeddc0SDimitry Andric case SkipPast::ReferenceThenPointer: 49204eeddc0SDimitry Andric StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); 49304eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef))) 49404eeddc0SDimitry Andric return Val->getPointeeLoc(); 49504eeddc0SDimitry Andric return LocPastRef; 49604eeddc0SDimitry Andric } 49704eeddc0SDimitry Andric llvm_unreachable("bad SkipPast kind"); 49804eeddc0SDimitry Andric } 49904eeddc0SDimitry Andric 50004eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc, 50104eeddc0SDimitry Andric SkipPast SP) const { 50204eeddc0SDimitry Andric return skip(*const_cast<StorageLocation *>(&Loc), SP); 50304eeddc0SDimitry Andric } 50404eeddc0SDimitry Andric 50581ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) { 50681ad6265SDimitry Andric DACtx->addFlowConditionConstraint(*FlowConditionToken, Val); 50781ad6265SDimitry Andric } 50881ad6265SDimitry Andric 50981ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const { 51081ad6265SDimitry Andric return DACtx->flowConditionImplies(*FlowConditionToken, Val); 51181ad6265SDimitry Andric } 51281ad6265SDimitry Andric 513*fcaf7f86SDimitry Andric void Environment::dump() const { 514*fcaf7f86SDimitry Andric DACtx->dumpFlowCondition(*FlowConditionToken); 515*fcaf7f86SDimitry Andric } 516*fcaf7f86SDimitry Andric 51704eeddc0SDimitry Andric } // namespace dataflow 51804eeddc0SDimitry Andric } // namespace clang 519