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 203*972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const { 204*972a253aSDimitry Andric Environment Env(*this); 205*972a253aSDimitry Andric 206*972a253aSDimitry Andric // FIXME: Currently this only works if the callee is never a method and the 207*972a253aSDimitry Andric // same callee is never analyzed from multiple separate callsites. To 208*972a253aSDimitry Andric // generalize this, we'll need to store a "context" field (probably a stack of 209*972a253aSDimitry Andric // `const CallExpr *`s) in the `Environment`, and then change the 210*972a253aSDimitry Andric // `DataflowAnalysisContext` class to hold a map from contexts to "frames", 211*972a253aSDimitry Andric // where each frame stores its own version of what are currently the 212*972a253aSDimitry Andric // `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields. 213*972a253aSDimitry Andric 214*972a253aSDimitry Andric const auto *FuncDecl = Call->getDirectCallee(); 215*972a253aSDimitry Andric assert(FuncDecl != nullptr); 216*972a253aSDimitry Andric assert(FuncDecl->getBody() != nullptr); 217*972a253aSDimitry Andric // FIXME: In order to allow the callee to reference globals, we probably need 218*972a253aSDimitry Andric // to call `initGlobalVars` here in some way. 219*972a253aSDimitry Andric 220*972a253aSDimitry Andric auto ParamIt = FuncDecl->param_begin(); 221*972a253aSDimitry Andric auto ArgIt = Call->arg_begin(); 222*972a253aSDimitry Andric auto ArgEnd = Call->arg_end(); 223*972a253aSDimitry Andric 224*972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include 225*972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs. 226*972a253aSDimitry Andric for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) { 227*972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end()); 228*972a253aSDimitry Andric 229*972a253aSDimitry Andric const VarDecl *Param = *ParamIt; 230*972a253aSDimitry Andric const Expr *Arg = *ArgIt; 231*972a253aSDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); 232*972a253aSDimitry Andric assert(ArgLoc != nullptr); 233*972a253aSDimitry Andric Env.setStorageLocation(*Param, *ArgLoc); 234*972a253aSDimitry Andric } 235*972a253aSDimitry Andric 236*972a253aSDimitry Andric return Env; 237*972a253aSDimitry Andric } 238*972a253aSDimitry Andric 2391fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 2401fd87a68SDimitry Andric Environment::ValueModel &Model) const { 24104eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 2421fd87a68SDimitry Andric 2431fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 2441fd87a68SDimitry Andric return false; 2451fd87a68SDimitry Andric 2461fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 2471fd87a68SDimitry Andric return false; 2481fd87a68SDimitry Andric 24981ad6265SDimitry Andric // Compare the contents for the intersection of their domains. 2501fd87a68SDimitry Andric for (auto &Entry : LocToVal) { 2511fd87a68SDimitry Andric const StorageLocation *Loc = Entry.first; 2521fd87a68SDimitry Andric assert(Loc != nullptr); 2531fd87a68SDimitry Andric 2541fd87a68SDimitry Andric Value *Val = Entry.second; 2551fd87a68SDimitry Andric assert(Val != nullptr); 2561fd87a68SDimitry Andric 2571fd87a68SDimitry Andric auto It = Other.LocToVal.find(Loc); 2581fd87a68SDimitry Andric if (It == Other.LocToVal.end()) 25981ad6265SDimitry Andric continue; 2601fd87a68SDimitry Andric assert(It->second != nullptr); 2611fd87a68SDimitry Andric 26281ad6265SDimitry Andric if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model)) 2631fd87a68SDimitry Andric return false; 2641fd87a68SDimitry Andric } 2651fd87a68SDimitry Andric 2661fd87a68SDimitry Andric return true; 26704eeddc0SDimitry Andric } 26804eeddc0SDimitry Andric 26904eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other, 2701fd87a68SDimitry Andric Environment::ValueModel &Model) { 27104eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 27204eeddc0SDimitry Andric 27304eeddc0SDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 27404eeddc0SDimitry Andric 27581ad6265SDimitry Andric Environment JoinedEnv(*DACtx); 27681ad6265SDimitry Andric 27781ad6265SDimitry Andric JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 27881ad6265SDimitry Andric if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size()) 27904eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 28004eeddc0SDimitry Andric 28181ad6265SDimitry Andric JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc); 28281ad6265SDimitry Andric if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size()) 28304eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 28404eeddc0SDimitry Andric 28581ad6265SDimitry Andric JoinedEnv.MemberLocToStruct = 28681ad6265SDimitry Andric intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct); 28781ad6265SDimitry Andric if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size()) 28881ad6265SDimitry Andric Effect = LatticeJoinEffect::Changed; 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric // FIXME: set `Effect` as needed. 29181ad6265SDimitry Andric JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions( 29281ad6265SDimitry Andric *FlowConditionToken, *Other.FlowConditionToken); 29381ad6265SDimitry Andric 29481ad6265SDimitry Andric for (auto &Entry : LocToVal) { 29504eeddc0SDimitry Andric const StorageLocation *Loc = Entry.first; 29604eeddc0SDimitry Andric assert(Loc != nullptr); 29704eeddc0SDimitry Andric 29804eeddc0SDimitry Andric Value *Val = Entry.second; 29904eeddc0SDimitry Andric assert(Val != nullptr); 30004eeddc0SDimitry Andric 30104eeddc0SDimitry Andric auto It = Other.LocToVal.find(Loc); 30204eeddc0SDimitry Andric if (It == Other.LocToVal.end()) 30304eeddc0SDimitry Andric continue; 30404eeddc0SDimitry Andric assert(It->second != nullptr); 30504eeddc0SDimitry Andric 30681ad6265SDimitry Andric if (Val == It->second) { 30781ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, Val}); 30804eeddc0SDimitry Andric continue; 30904eeddc0SDimitry Andric } 31004eeddc0SDimitry Andric 31181ad6265SDimitry Andric if (Value *MergedVal = mergeDistinctValues( 31281ad6265SDimitry Andric Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model)) 31381ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, MergedVal}); 31404eeddc0SDimitry Andric } 31581ad6265SDimitry Andric if (LocToVal.size() != JoinedEnv.LocToVal.size()) 31604eeddc0SDimitry Andric Effect = LatticeJoinEffect::Changed; 31704eeddc0SDimitry Andric 31881ad6265SDimitry Andric *this = std::move(JoinedEnv); 31981ad6265SDimitry Andric 32004eeddc0SDimitry Andric return Effect; 32104eeddc0SDimitry Andric } 32204eeddc0SDimitry Andric 32304eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 32481ad6265SDimitry Andric return DACtx->getStableStorageLocation(Type); 32504eeddc0SDimitry Andric } 32604eeddc0SDimitry Andric 32704eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 32804eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 32904eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 33004eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 33181ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 33204eeddc0SDimitry Andric } 33304eeddc0SDimitry Andric 33404eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 33504eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 33604eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 33704eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 33881ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 33904eeddc0SDimitry Andric } 34004eeddc0SDimitry Andric 34104eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 34204eeddc0SDimitry Andric assert(DeclToLoc.find(&D) == DeclToLoc.end()); 34304eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 34404eeddc0SDimitry Andric } 34504eeddc0SDimitry Andric 34604eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D, 34704eeddc0SDimitry Andric SkipPast SP) const { 34804eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 34904eeddc0SDimitry Andric return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); 35004eeddc0SDimitry Andric } 35104eeddc0SDimitry Andric 35204eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 35381ad6265SDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 35481ad6265SDimitry Andric assert(ExprToLoc.find(&CanonE) == ExprToLoc.end()); 35581ad6265SDimitry Andric ExprToLoc[&CanonE] = &Loc; 35604eeddc0SDimitry Andric } 35704eeddc0SDimitry Andric 35804eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E, 35904eeddc0SDimitry Andric SkipPast SP) const { 36081ad6265SDimitry Andric // FIXME: Add a test with parens. 36181ad6265SDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 36204eeddc0SDimitry Andric return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 36304eeddc0SDimitry Andric } 36404eeddc0SDimitry Andric 36504eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const { 36604eeddc0SDimitry Andric return DACtx->getThisPointeeStorageLocation(); 36704eeddc0SDimitry Andric } 36804eeddc0SDimitry Andric 36981ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 37081ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 37181ad6265SDimitry Andric } 37281ad6265SDimitry Andric 37304eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 37404eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 37504eeddc0SDimitry Andric 37604eeddc0SDimitry Andric if (auto *StructVal = dyn_cast<StructValue>(&Val)) { 37704eeddc0SDimitry Andric auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc); 37804eeddc0SDimitry Andric 37904eeddc0SDimitry Andric const QualType Type = AggregateLoc.getType(); 38004eeddc0SDimitry Andric assert(Type->isStructureOrClassType()); 38104eeddc0SDimitry Andric 38281ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 38304eeddc0SDimitry Andric assert(Field != nullptr); 38481ad6265SDimitry Andric StorageLocation &FieldLoc = AggregateLoc.getChild(*Field); 38581ad6265SDimitry Andric MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field); 38681ad6265SDimitry Andric if (auto *FieldVal = StructVal->getChild(*Field)) 38781ad6265SDimitry Andric setValue(FieldLoc, *FieldVal); 38804eeddc0SDimitry Andric } 38904eeddc0SDimitry Andric } 39081ad6265SDimitry Andric 391*972a253aSDimitry Andric auto It = MemberLocToStruct.find(&Loc); 392*972a253aSDimitry Andric if (It != MemberLocToStruct.end()) { 39381ad6265SDimitry Andric // `Loc` is the location of a struct member so we need to also update the 39481ad6265SDimitry Andric // value of the member in the corresponding `StructValue`. 39581ad6265SDimitry Andric 396*972a253aSDimitry Andric assert(It->second.first != nullptr); 397*972a253aSDimitry Andric StructValue &StructVal = *It->second.first; 39881ad6265SDimitry Andric 399*972a253aSDimitry Andric assert(It->second.second != nullptr); 400*972a253aSDimitry Andric const ValueDecl &Member = *It->second.second; 40181ad6265SDimitry Andric 40281ad6265SDimitry Andric StructVal.setChild(Member, Val); 40381ad6265SDimitry Andric } 40404eeddc0SDimitry Andric } 40504eeddc0SDimitry Andric 40604eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 40704eeddc0SDimitry Andric auto It = LocToVal.find(&Loc); 40804eeddc0SDimitry Andric return It == LocToVal.end() ? nullptr : It->second; 40904eeddc0SDimitry Andric } 41004eeddc0SDimitry Andric 41104eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { 41204eeddc0SDimitry Andric auto *Loc = getStorageLocation(D, SP); 41304eeddc0SDimitry Andric if (Loc == nullptr) 41404eeddc0SDimitry Andric return nullptr; 41504eeddc0SDimitry Andric return getValue(*Loc); 41604eeddc0SDimitry Andric } 41704eeddc0SDimitry Andric 41804eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const { 41904eeddc0SDimitry Andric auto *Loc = getStorageLocation(E, SP); 42004eeddc0SDimitry Andric if (Loc == nullptr) 42104eeddc0SDimitry Andric return nullptr; 42204eeddc0SDimitry Andric return getValue(*Loc); 42304eeddc0SDimitry Andric } 42404eeddc0SDimitry Andric 42504eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 42604eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 42781ad6265SDimitry Andric int CreatedValuesCount = 0; 42881ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 42981ad6265SDimitry Andric CreatedValuesCount); 43081ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 43181ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 43281ad6265SDimitry Andric << '\n'; 43381ad6265SDimitry Andric } 43481ad6265SDimitry Andric return Val; 43504eeddc0SDimitry Andric } 43604eeddc0SDimitry Andric 43704eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 43881ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 43981ad6265SDimitry Andric int &CreatedValuesCount) { 44004eeddc0SDimitry Andric assert(!Type.isNull()); 44104eeddc0SDimitry Andric 44281ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 44381ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 44481ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 44581ad6265SDimitry Andric return nullptr; 44681ad6265SDimitry Andric 44781ad6265SDimitry Andric if (Type->isBooleanType()) { 44881ad6265SDimitry Andric CreatedValuesCount++; 44981ad6265SDimitry Andric return &makeAtomicBoolValue(); 45081ad6265SDimitry Andric } 45181ad6265SDimitry Andric 45204eeddc0SDimitry Andric if (Type->isIntegerType()) { 45381ad6265SDimitry Andric CreatedValuesCount++; 45404eeddc0SDimitry Andric return &takeOwnership(std::make_unique<IntegerValue>()); 45504eeddc0SDimitry Andric } 45604eeddc0SDimitry Andric 45704eeddc0SDimitry Andric if (Type->isReferenceType()) { 45881ad6265SDimitry Andric CreatedValuesCount++; 45981ad6265SDimitry Andric QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType(); 46004eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 46104eeddc0SDimitry Andric 46281ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 46381ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 46481ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 46504eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 46604eeddc0SDimitry Andric 46704eeddc0SDimitry Andric if (PointeeVal != nullptr) 46804eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 46904eeddc0SDimitry Andric } 47004eeddc0SDimitry Andric 47104eeddc0SDimitry Andric return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 47204eeddc0SDimitry Andric } 47304eeddc0SDimitry Andric 47404eeddc0SDimitry Andric if (Type->isPointerType()) { 47581ad6265SDimitry Andric CreatedValuesCount++; 47681ad6265SDimitry Andric QualType PointeeType = Type->castAs<PointerType>()->getPointeeType(); 47704eeddc0SDimitry Andric auto &PointeeLoc = createStorageLocation(PointeeType); 47804eeddc0SDimitry Andric 47981ad6265SDimitry Andric if (Visited.insert(PointeeType.getCanonicalType()).second) { 48081ad6265SDimitry Andric Value *PointeeVal = createValueUnlessSelfReferential( 48181ad6265SDimitry Andric PointeeType, Visited, Depth, CreatedValuesCount); 48204eeddc0SDimitry Andric Visited.erase(PointeeType.getCanonicalType()); 48304eeddc0SDimitry Andric 48404eeddc0SDimitry Andric if (PointeeVal != nullptr) 48504eeddc0SDimitry Andric setValue(PointeeLoc, *PointeeVal); 48604eeddc0SDimitry Andric } 48704eeddc0SDimitry Andric 48804eeddc0SDimitry Andric return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 48904eeddc0SDimitry Andric } 49004eeddc0SDimitry Andric 49104eeddc0SDimitry Andric if (Type->isStructureOrClassType()) { 49281ad6265SDimitry Andric CreatedValuesCount++; 49304eeddc0SDimitry Andric // FIXME: Initialize only fields that are accessed in the context that is 49404eeddc0SDimitry Andric // being analyzed. 49504eeddc0SDimitry Andric llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 49681ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) { 49704eeddc0SDimitry Andric assert(Field != nullptr); 49804eeddc0SDimitry Andric 49904eeddc0SDimitry Andric QualType FieldType = Field->getType(); 50004eeddc0SDimitry Andric if (Visited.contains(FieldType.getCanonicalType())) 50104eeddc0SDimitry Andric continue; 50204eeddc0SDimitry Andric 50304eeddc0SDimitry Andric Visited.insert(FieldType.getCanonicalType()); 50481ad6265SDimitry Andric if (auto *FieldValue = createValueUnlessSelfReferential( 50581ad6265SDimitry Andric FieldType, Visited, Depth + 1, CreatedValuesCount)) 50681ad6265SDimitry Andric FieldValues.insert({Field, FieldValue}); 50704eeddc0SDimitry Andric Visited.erase(FieldType.getCanonicalType()); 50804eeddc0SDimitry Andric } 50904eeddc0SDimitry Andric 51004eeddc0SDimitry Andric return &takeOwnership( 51104eeddc0SDimitry Andric std::make_unique<StructValue>(std::move(FieldValues))); 51204eeddc0SDimitry Andric } 51304eeddc0SDimitry Andric 51404eeddc0SDimitry Andric return nullptr; 51504eeddc0SDimitry Andric } 51604eeddc0SDimitry Andric 51704eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 51804eeddc0SDimitry Andric switch (SP) { 51904eeddc0SDimitry Andric case SkipPast::None: 52004eeddc0SDimitry Andric return Loc; 52104eeddc0SDimitry Andric case SkipPast::Reference: 52204eeddc0SDimitry Andric // References cannot be chained so we only need to skip past one level of 52304eeddc0SDimitry Andric // indirection. 52404eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 52581ad6265SDimitry Andric return Val->getReferentLoc(); 52604eeddc0SDimitry Andric return Loc; 52704eeddc0SDimitry Andric case SkipPast::ReferenceThenPointer: 52804eeddc0SDimitry Andric StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); 52904eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef))) 53004eeddc0SDimitry Andric return Val->getPointeeLoc(); 53104eeddc0SDimitry Andric return LocPastRef; 53204eeddc0SDimitry Andric } 53304eeddc0SDimitry Andric llvm_unreachable("bad SkipPast kind"); 53404eeddc0SDimitry Andric } 53504eeddc0SDimitry Andric 53604eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc, 53704eeddc0SDimitry Andric SkipPast SP) const { 53804eeddc0SDimitry Andric return skip(*const_cast<StorageLocation *>(&Loc), SP); 53904eeddc0SDimitry Andric } 54004eeddc0SDimitry Andric 54181ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) { 54281ad6265SDimitry Andric DACtx->addFlowConditionConstraint(*FlowConditionToken, Val); 54381ad6265SDimitry Andric } 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const { 54681ad6265SDimitry Andric return DACtx->flowConditionImplies(*FlowConditionToken, Val); 54781ad6265SDimitry Andric } 54881ad6265SDimitry Andric 549fcaf7f86SDimitry Andric void Environment::dump() const { 550fcaf7f86SDimitry Andric DACtx->dumpFlowCondition(*FlowConditionToken); 551fcaf7f86SDimitry Andric } 552fcaf7f86SDimitry Andric 55304eeddc0SDimitry Andric } // namespace dataflow 55404eeddc0SDimitry Andric } // namespace clang 555