1 //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an Environment class that is used by dataflow analyses 10 // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 11 // program at given program points. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/Type.h" 19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 20 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 21 #include "clang/Analysis/FlowSensitive/Value.h" 22 #include "llvm/ADT/DenseMap.h" 23 #include "llvm/ADT/DenseSet.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include <cassert> 26 #include <memory> 27 #include <utility> 28 29 namespace clang { 30 namespace dataflow { 31 32 /// Returns a map consisting of key-value entries that are present in both maps. 33 template <typename K, typename V> 34 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 35 const llvm::DenseMap<K, V> &Map2) { 36 llvm::DenseMap<K, V> Result; 37 for (auto &Entry : Map1) { 38 auto It = Map2.find(Entry.first); 39 if (It != Map2.end() && Entry.second == It->second) 40 Result.insert({Entry.first, Entry.second}); 41 } 42 return Result; 43 } 44 45 /// Returns true if and only if `Val1` is equivalent to `Val2`. 46 static bool equivalentValues(QualType Type, Value *Val1, Value *Val2, 47 Environment::ValueModel &Model) { 48 if (Val1 == Val2) 49 return true; 50 51 if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) { 52 auto *IndVal2 = cast<IndirectionValue>(Val2); 53 assert(IndVal1->getKind() == IndVal2->getKind()); 54 return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc(); 55 } 56 57 return Model.compareEquivalent(Type, *Val1, *Val2); 58 } 59 60 /// Initializes a global storage value. 61 static void initGlobalVar(const VarDecl &D, Environment &Env) { 62 if (!D.hasGlobalStorage() || 63 Env.getStorageLocation(D, SkipPast::None) != nullptr) 64 return; 65 66 auto &Loc = Env.createStorageLocation(D); 67 Env.setStorageLocation(D, Loc); 68 if (auto *Val = Env.createValue(D.getType())) 69 Env.setValue(Loc, *Val); 70 } 71 72 /// Initializes a global storage value. 73 static void initGlobalVar(const Decl &D, Environment &Env) { 74 if (auto *V = dyn_cast<VarDecl>(&D)) 75 initGlobalVar(*V, Env); 76 } 77 78 /// Initializes global storage values that are declared or referenced from 79 /// sub-statements of `S`. 80 // FIXME: Add support for resetting globals after function calls to enable 81 // the implementation of sound analyses. 82 static void initGlobalVars(const Stmt &S, Environment &Env) { 83 for (auto *Child : S.children()) { 84 if (Child != nullptr) 85 initGlobalVars(*Child, Env); 86 } 87 88 if (auto *DS = dyn_cast<DeclStmt>(&S)) { 89 if (DS->isSingleDecl()) { 90 initGlobalVar(*DS->getSingleDecl(), Env); 91 } else { 92 for (auto *D : DS->getDeclGroup()) 93 initGlobalVar(*D, Env); 94 } 95 } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 96 initGlobalVar(*E->getDecl(), Env); 97 } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 98 initGlobalVar(*E->getMemberDecl(), Env); 99 } 100 } 101 102 Environment::Environment(DataflowAnalysisContext &DACtx, 103 const DeclContext &DeclCtx) 104 : Environment(DACtx) { 105 if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) { 106 assert(FuncDecl->getBody() != nullptr); 107 initGlobalVars(*FuncDecl->getBody(), *this); 108 for (const auto *ParamDecl : FuncDecl->parameters()) { 109 assert(ParamDecl != nullptr); 110 auto &ParamLoc = createStorageLocation(*ParamDecl); 111 setStorageLocation(*ParamDecl, ParamLoc); 112 if (Value *ParamVal = createValue(ParamDecl->getType())) 113 setValue(ParamLoc, *ParamVal); 114 } 115 } 116 117 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) { 118 if (!MethodDecl->isStatic()) { 119 QualType ThisPointeeType = MethodDecl->getThisObjectType(); 120 // FIXME: Add support for union types. 121 if (!ThisPointeeType->isUnionType()) { 122 auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType); 123 DACtx.setThisPointeeStorageLocation(ThisPointeeLoc); 124 if (Value *ThisPointeeVal = createValue(ThisPointeeType)) 125 setValue(ThisPointeeLoc, *ThisPointeeVal); 126 } 127 } 128 } 129 } 130 131 bool Environment::equivalentTo(const Environment &Other, 132 Environment::ValueModel &Model) const { 133 assert(DACtx == Other.DACtx); 134 135 if (DeclToLoc != Other.DeclToLoc) 136 return false; 137 138 if (ExprToLoc != Other.ExprToLoc) 139 return false; 140 141 if (MemberLocToStruct != Other.MemberLocToStruct) 142 return false; 143 144 if (LocToVal.size() != Other.LocToVal.size()) 145 return false; 146 147 for (auto &Entry : LocToVal) { 148 const StorageLocation *Loc = Entry.first; 149 assert(Loc != nullptr); 150 151 Value *Val = Entry.second; 152 assert(Val != nullptr); 153 154 auto It = Other.LocToVal.find(Loc); 155 if (It == Other.LocToVal.end()) 156 return false; 157 assert(It->second != nullptr); 158 159 if (!equivalentValues(Loc->getType(), Val, It->second, Model)) 160 return false; 161 } 162 163 return true; 164 } 165 166 LatticeJoinEffect Environment::join(const Environment &Other, 167 Environment::ValueModel &Model) { 168 assert(DACtx == Other.DACtx); 169 170 auto Effect = LatticeJoinEffect::Unchanged; 171 172 const unsigned DeclToLocSizeBefore = DeclToLoc.size(); 173 DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 174 if (DeclToLocSizeBefore != DeclToLoc.size()) 175 Effect = LatticeJoinEffect::Changed; 176 177 const unsigned ExprToLocSizeBefore = ExprToLoc.size(); 178 ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc); 179 if (ExprToLocSizeBefore != ExprToLoc.size()) 180 Effect = LatticeJoinEffect::Changed; 181 182 const unsigned MemberLocToStructSizeBefore = MemberLocToStruct.size(); 183 MemberLocToStruct = 184 intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct); 185 if (MemberLocToStructSizeBefore != MemberLocToStruct.size()) 186 Effect = LatticeJoinEffect::Changed; 187 188 // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign 189 // values to storage locations while this code iterates over the current 190 // assignments. 191 llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal = 192 std::move(LocToVal); 193 for (auto &Entry : OldLocToVal) { 194 const StorageLocation *Loc = Entry.first; 195 assert(Loc != nullptr); 196 197 Value *Val = Entry.second; 198 assert(Val != nullptr); 199 200 auto It = Other.LocToVal.find(Loc); 201 if (It == Other.LocToVal.end()) 202 continue; 203 assert(It->second != nullptr); 204 205 if (equivalentValues(Loc->getType(), Val, It->second, Model)) { 206 LocToVal.insert({Loc, Val}); 207 continue; 208 } 209 210 // FIXME: Consider destroying `MergedValue` immediately if 211 // `ValueModel::merge` returns false to avoid storing unneeded values in 212 // `DACtx`. 213 if (Value *MergedVal = createValue(Loc->getType())) 214 if (Model.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this)) 215 LocToVal.insert({Loc, MergedVal}); 216 } 217 if (OldLocToVal.size() != LocToVal.size()) 218 Effect = LatticeJoinEffect::Changed; 219 220 return Effect; 221 } 222 223 StorageLocation &Environment::createStorageLocation(QualType Type) { 224 assert(!Type.isNull()); 225 if (Type->isStructureOrClassType() || Type->isUnionType()) { 226 // FIXME: Explore options to avoid eager initialization of fields as some of 227 // them might not be needed for a particular analysis. 228 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 229 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 230 FieldLocs.insert({Field, &createStorageLocation(Field->getType())}); 231 } 232 return takeOwnership( 233 std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); 234 } 235 return takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); 236 } 237 238 StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 239 // Evaluated declarations are always assigned the same storage locations to 240 // ensure that the environment stabilizes across loop iterations. Storage 241 // locations for evaluated declarations are stored in the analysis context. 242 if (auto *Loc = DACtx->getStorageLocation(D)) 243 return *Loc; 244 auto &Loc = createStorageLocation(D.getType()); 245 DACtx->setStorageLocation(D, Loc); 246 return Loc; 247 } 248 249 StorageLocation &Environment::createStorageLocation(const Expr &E) { 250 // Evaluated expressions are always assigned the same storage locations to 251 // ensure that the environment stabilizes across loop iterations. Storage 252 // locations for evaluated expressions are stored in the analysis context. 253 if (auto *Loc = DACtx->getStorageLocation(E)) 254 return *Loc; 255 auto &Loc = createStorageLocation(E.getType()); 256 DACtx->setStorageLocation(E, Loc); 257 return Loc; 258 } 259 260 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 261 assert(DeclToLoc.find(&D) == DeclToLoc.end()); 262 DeclToLoc[&D] = &Loc; 263 } 264 265 StorageLocation *Environment::getStorageLocation(const ValueDecl &D, 266 SkipPast SP) const { 267 auto It = DeclToLoc.find(&D); 268 return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); 269 } 270 271 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 272 assert(ExprToLoc.find(&E) == ExprToLoc.end()); 273 ExprToLoc[&E] = &Loc; 274 } 275 276 StorageLocation *Environment::getStorageLocation(const Expr &E, 277 SkipPast SP) const { 278 auto It = ExprToLoc.find(&E); 279 return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 280 } 281 282 StorageLocation *Environment::getThisPointeeStorageLocation() const { 283 return DACtx->getThisPointeeStorageLocation(); 284 } 285 286 void Environment::setValue(const StorageLocation &Loc, Value &Val) { 287 LocToVal[&Loc] = &Val; 288 289 if (auto *StructVal = dyn_cast<StructValue>(&Val)) { 290 auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc); 291 292 const QualType Type = AggregateLoc.getType(); 293 assert(Type->isStructureOrClassType()); 294 295 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 296 assert(Field != nullptr); 297 StorageLocation &FieldLoc = AggregateLoc.getChild(*Field); 298 MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field); 299 setValue(FieldLoc, StructVal->getChild(*Field)); 300 } 301 } 302 303 auto IT = MemberLocToStruct.find(&Loc); 304 if (IT != MemberLocToStruct.end()) { 305 // `Loc` is the location of a struct member so we need to also update the 306 // value of the member in the corresponding `StructValue`. 307 308 assert(IT->second.first != nullptr); 309 StructValue &StructVal = *IT->second.first; 310 311 assert(IT->second.second != nullptr); 312 const ValueDecl &Member = *IT->second.second; 313 314 StructVal.setChild(Member, Val); 315 } 316 } 317 318 Value *Environment::getValue(const StorageLocation &Loc) const { 319 auto It = LocToVal.find(&Loc); 320 return It == LocToVal.end() ? nullptr : It->second; 321 } 322 323 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { 324 auto *Loc = getStorageLocation(D, SP); 325 if (Loc == nullptr) 326 return nullptr; 327 return getValue(*Loc); 328 } 329 330 Value *Environment::getValue(const Expr &E, SkipPast SP) const { 331 auto *Loc = getStorageLocation(E, SP); 332 if (Loc == nullptr) 333 return nullptr; 334 return getValue(*Loc); 335 } 336 337 Value *Environment::createValue(QualType Type) { 338 llvm::DenseSet<QualType> Visited; 339 return createValueUnlessSelfReferential(Type, Visited); 340 } 341 342 Value *Environment::createValueUnlessSelfReferential( 343 QualType Type, llvm::DenseSet<QualType> &Visited) { 344 assert(!Type.isNull()); 345 346 if (Type->isIntegerType()) { 347 return &takeOwnership(std::make_unique<IntegerValue>()); 348 } 349 350 if (Type->isReferenceType()) { 351 QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType(); 352 auto &PointeeLoc = createStorageLocation(PointeeType); 353 354 if (!Visited.contains(PointeeType.getCanonicalType())) { 355 Visited.insert(PointeeType.getCanonicalType()); 356 Value *PointeeVal = 357 createValueUnlessSelfReferential(PointeeType, Visited); 358 Visited.erase(PointeeType.getCanonicalType()); 359 360 if (PointeeVal != nullptr) 361 setValue(PointeeLoc, *PointeeVal); 362 } 363 364 return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 365 } 366 367 if (Type->isPointerType()) { 368 QualType PointeeType = Type->getAs<PointerType>()->getPointeeType(); 369 auto &PointeeLoc = createStorageLocation(PointeeType); 370 371 if (!Visited.contains(PointeeType.getCanonicalType())) { 372 Visited.insert(PointeeType.getCanonicalType()); 373 Value *PointeeVal = 374 createValueUnlessSelfReferential(PointeeType, Visited); 375 Visited.erase(PointeeType.getCanonicalType()); 376 377 if (PointeeVal != nullptr) 378 setValue(PointeeLoc, *PointeeVal); 379 } 380 381 return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 382 } 383 384 if (Type->isStructureOrClassType()) { 385 // FIXME: Initialize only fields that are accessed in the context that is 386 // being analyzed. 387 llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 388 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 389 assert(Field != nullptr); 390 391 QualType FieldType = Field->getType(); 392 if (Visited.contains(FieldType.getCanonicalType())) 393 continue; 394 395 Visited.insert(FieldType.getCanonicalType()); 396 FieldValues.insert( 397 {Field, createValueUnlessSelfReferential(FieldType, Visited)}); 398 Visited.erase(FieldType.getCanonicalType()); 399 } 400 401 return &takeOwnership( 402 std::make_unique<StructValue>(std::move(FieldValues))); 403 } 404 405 return nullptr; 406 } 407 408 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 409 switch (SP) { 410 case SkipPast::None: 411 return Loc; 412 case SkipPast::Reference: 413 // References cannot be chained so we only need to skip past one level of 414 // indirection. 415 if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 416 return Val->getPointeeLoc(); 417 return Loc; 418 case SkipPast::ReferenceThenPointer: 419 StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); 420 if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef))) 421 return Val->getPointeeLoc(); 422 return LocPastRef; 423 } 424 llvm_unreachable("bad SkipPast kind"); 425 } 426 427 const StorageLocation &Environment::skip(const StorageLocation &Loc, 428 SkipPast SP) const { 429 return skip(*const_cast<StorageLocation *>(&Loc), SP); 430 } 431 432 } // namespace dataflow 433 } // namespace clang 434