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