1 //===-- DataflowEnvironment.h -----------------------------------*- 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 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 16 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 17 18 #include "clang/AST/Decl.h" 19 #include "clang/AST/DeclBase.h" 20 #include "clang/AST/Expr.h" 21 #include "clang/AST/Type.h" 22 #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" 23 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 24 #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 25 #include "clang/Analysis/FlowSensitive/Formula.h" 26 #include "clang/Analysis/FlowSensitive/Logger.h" 27 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 28 #include "clang/Analysis/FlowSensitive/Value.h" 29 #include "llvm/ADT/DenseMap.h" 30 #include "llvm/ADT/DenseSet.h" 31 #include "llvm/ADT/MapVector.h" 32 #include "llvm/Support/Compiler.h" 33 #include "llvm/Support/ErrorHandling.h" 34 #include <memory> 35 #include <type_traits> 36 #include <utility> 37 38 namespace clang { 39 namespace dataflow { 40 41 /// Indicates the result of a tentative comparison. 42 enum class ComparisonResult { 43 Same, 44 Different, 45 Unknown, 46 }; 47 48 /// Holds the state of the program (store and heap) at a given program point. 49 /// 50 /// WARNING: Symbolic values that are created by the environment for static 51 /// local and global variables are not currently invalidated on function calls. 52 /// This is unsound and should be taken into account when designing dataflow 53 /// analyses. 54 class Environment { 55 public: 56 /// Supplements `Environment` with non-standard comparison and join 57 /// operations. 58 class ValueModel { 59 public: 60 virtual ~ValueModel() = default; 61 62 /// Returns: 63 /// `Same`: `Val1` is equivalent to `Val2`, according to the model. 64 /// `Different`: `Val1` is distinct from `Val2`, according to the model. 65 /// `Unknown`: The model can't determine a relationship between `Val1` and 66 /// `Val2`. 67 /// 68 /// Requirements: 69 /// 70 /// `Val1` and `Val2` must be distinct. 71 /// 72 /// `Val1` and `Val2` must model values of type `Type`. 73 /// 74 /// `Val1` and `Val2` must be assigned to the same storage location in 75 /// `Env1` and `Env2` respectively. 76 virtual ComparisonResult compare(QualType Type, const Value &Val1, 77 const Environment &Env1, const Value &Val2, 78 const Environment &Env2) { 79 // FIXME: Consider adding QualType to RecordValue and removing the Type 80 // argument here. 81 return ComparisonResult::Unknown; 82 } 83 84 /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could 85 /// be a strict lattice join or a more general widening operation. 86 /// 87 /// If this function returns true, `MergedVal` will be assigned to a storage 88 /// location of type `Type` in `MergedEnv`. 89 /// 90 /// `Env1` and `Env2` can be used to query child values and path condition 91 /// implications of `Val1` and `Val2` respectively. 92 /// 93 /// Requirements: 94 /// 95 /// `Val1` and `Val2` must be distinct. 96 /// 97 /// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`. 98 /// 99 /// `Val1` and `Val2` must be assigned to the same storage location in 100 /// `Env1` and `Env2` respectively. 101 virtual bool merge(QualType Type, const Value &Val1, 102 const Environment &Env1, const Value &Val2, 103 const Environment &Env2, Value &MergedVal, 104 Environment &MergedEnv) { 105 return true; 106 } 107 108 /// This function may widen the current value -- replace it with an 109 /// approximation that can reach a fixed point more quickly than iterated 110 /// application of the transfer function alone. The previous value is 111 /// provided to inform the choice of widened value. The function must also 112 /// serve as a comparison operation, by indicating whether the widened value 113 /// is equivalent to the previous value. 114 /// 115 /// Returns either: 116 /// 117 /// `nullptr`, if this value is not of interest to the model, or 118 /// 119 /// `&Prev`, if the widened value is equivalent to `Prev`, or 120 /// 121 /// A non-null value that approximates `Current`. `Prev` is available to 122 /// inform the chosen approximation. 123 /// 124 /// `PrevEnv` and `CurrentEnv` can be used to query child values and path 125 /// condition implications of `Prev` and `Current`, respectively. 126 /// 127 /// Requirements: 128 /// 129 /// `Prev` and `Current` must model values of type `Type`. 130 /// 131 /// `Prev` and `Current` must be assigned to the same storage location in 132 /// `PrevEnv` and `CurrentEnv`, respectively. 133 virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, 134 Value &Current, Environment &CurrentEnv) { 135 // The default implementation reduces to just comparison, since comparison 136 // is required by the API, even if no widening is performed. 137 switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { 138 case ComparisonResult::Same: 139 return &Prev; 140 case ComparisonResult::Different: 141 return &Current; 142 case ComparisonResult::Unknown: 143 return nullptr; 144 } 145 llvm_unreachable("all cases in switch covered"); 146 } 147 }; 148 149 /// Creates an environment that uses `DACtx` to store objects that encompass 150 /// the state of a program. 151 explicit Environment(DataflowAnalysisContext &DACtx); 152 153 // Copy-constructor is private, Environments should not be copied. See fork(). 154 Environment &operator=(const Environment &Other) = delete; 155 156 Environment(Environment &&Other) = default; 157 Environment &operator=(Environment &&Other) = default; 158 159 /// Creates an environment that uses `DACtx` to store objects that encompass 160 /// the state of a program. 161 /// 162 /// If `DeclCtx` is a function, initializes the environment with symbolic 163 /// representations of the function parameters. 164 /// 165 /// If `DeclCtx` is a non-static member function, initializes the environment 166 /// with a symbolic representation of the `this` pointee. 167 Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); 168 169 /// Assigns storage locations and values to all parameters, captures, global 170 /// variables, fields and functions referenced in the function currently being 171 /// analyzed. 172 /// 173 /// Requirements: 174 /// 175 /// The function must have a body. 176 void initialize(); 177 178 /// Returns a new environment that is a copy of this one. 179 /// 180 /// The state of the program is initially the same, but can be mutated without 181 /// affecting the original. 182 /// 183 /// However the original should not be further mutated, as this may interfere 184 /// with the fork. (In practice, values are stored independently, but the 185 /// forked flow condition references the original). 186 Environment fork() const; 187 188 /// Creates and returns an environment to use for an inline analysis of the 189 /// callee. Uses the storage location from each argument in the `Call` as the 190 /// storage location for the corresponding parameter in the callee. 191 /// 192 /// Requirements: 193 /// 194 /// The callee of `Call` must be a `FunctionDecl`. 195 /// 196 /// The body of the callee must not reference globals. 197 /// 198 /// The arguments of `Call` must map 1:1 to the callee's parameters. 199 Environment pushCall(const CallExpr *Call) const; 200 Environment pushCall(const CXXConstructExpr *Call) const; 201 202 /// Moves gathered information back into `this` from a `CalleeEnv` created via 203 /// `pushCall`. 204 void popCall(const CallExpr *Call, const Environment &CalleeEnv); 205 void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv); 206 207 /// Returns true if and only if the environment is equivalent to `Other`, i.e 208 /// the two environments: 209 /// - have the same mappings from declarations to storage locations, 210 /// - have the same mappings from expressions to storage locations, 211 /// - have the same or equivalent (according to `Model`) values assigned to 212 /// the same storage locations. 213 /// 214 /// Requirements: 215 /// 216 /// `Other` and `this` must use the same `DataflowAnalysisContext`. 217 bool equivalentTo(const Environment &Other, 218 Environment::ValueModel &Model) const; 219 220 /// Joins two environments by taking the intersection of storage locations and 221 /// values that are stored in them. Distinct values that are assigned to the 222 /// same storage locations in `EnvA` and `EnvB` are merged using `Model`. 223 /// 224 /// Requirements: 225 /// 226 /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`. 227 static Environment join(const Environment &EnvA, const Environment &EnvB, 228 Environment::ValueModel &Model); 229 230 /// Widens the environment point-wise, using `PrevEnv` as needed to inform the 231 /// approximation. 232 /// 233 /// Requirements: 234 /// 235 /// `PrevEnv` must be the immediate previous version of the environment. 236 /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. 237 LatticeJoinEffect widen(const Environment &PrevEnv, 238 Environment::ValueModel &Model); 239 240 // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, 241 // `getStableStorageLocation`, or something more appropriate. 242 243 /// Creates a storage location appropriate for `Type`. Does not assign a value 244 /// to the returned storage location in the environment. 245 /// 246 /// Requirements: 247 /// 248 /// `Type` must not be null. 249 StorageLocation &createStorageLocation(QualType Type); 250 251 /// Creates a storage location for `D`. Does not assign the returned storage 252 /// location to `D` in the environment. Does not assign a value to the 253 /// returned storage location in the environment. 254 StorageLocation &createStorageLocation(const ValueDecl &D); 255 256 /// Creates a storage location for `E`. Does not assign the returned storage 257 /// location to `E` in the environment. Does not assign a value to the 258 /// returned storage location in the environment. 259 StorageLocation &createStorageLocation(const Expr &E); 260 261 /// Assigns `Loc` as the storage location of `D` in the environment. 262 /// 263 /// Requirements: 264 /// 265 /// `D` must not already have a storage location in the environment. 266 void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); 267 268 /// Returns the storage location assigned to `D` in the environment, or null 269 /// if `D` isn't assigned a storage location in the environment. 270 StorageLocation *getStorageLocation(const ValueDecl &D) const; 271 272 /// Removes the location assigned to `D` in the environment (if any). 273 void removeDecl(const ValueDecl &D); 274 275 /// Assigns `Loc` as the storage location of the glvalue `E` in the 276 /// environment. 277 /// 278 /// Requirements: 279 /// 280 /// `E` must not be assigned a storage location in the environment. 281 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 282 void setStorageLocation(const Expr &E, StorageLocation &Loc); 283 284 /// Returns the storage location assigned to the glvalue `E` in the 285 /// environment, or null if `E` isn't assigned a storage location in the 286 /// environment. 287 /// 288 /// Requirements: 289 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 290 StorageLocation *getStorageLocation(const Expr &E) const; 291 292 /// Returns the result of casting `getStorageLocation(...)` to a subclass of 293 /// `StorageLocation` (using `cast_or_null<T>`). 294 /// This assert-fails if the result of `getStorageLocation(...)` is not of 295 /// type `T *`; if the storage location is not guaranteed to have type `T *`, 296 /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead. 297 template <typename T> 298 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> 299 get(const ValueDecl &D) const { 300 return cast_or_null<T>(getStorageLocation(D)); 301 } 302 template <typename T> 303 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> 304 get(const Expr &E) const { 305 return cast_or_null<T>(getStorageLocation(E)); 306 } 307 308 /// Returns the storage location assigned to the `this` pointee in the 309 /// environment or null if the `this` pointee has no assigned storage location 310 /// in the environment. 311 RecordStorageLocation *getThisPointeeStorageLocation() const { 312 return ThisPointeeLoc; 313 } 314 315 /// Sets the storage location assigned to the `this` pointee in the 316 /// environment. 317 void setThisPointeeStorageLocation(RecordStorageLocation &Loc) { 318 ThisPointeeLoc = &Loc; 319 } 320 321 /// Returns the location of the result object for a record-type prvalue. 322 /// 323 /// In C++, prvalues of record type serve only a limited purpose: They can 324 /// only be used to initialize a result object (e.g. a variable or a 325 /// temporary). This function returns the location of that result object. 326 /// 327 /// When creating a prvalue of record type, we already need the storage 328 /// location of the result object to pass in `this`, even though prvalues are 329 /// otherwise not associated with storage locations. 330 /// 331 /// FIXME: Currently, this simply returns a stable storage location for `E`, 332 /// but this doesn't do the right thing in scenarios like the following: 333 /// ``` 334 /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar); 335 /// ``` 336 /// Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage 337 /// locations, when in fact their storage locations should be the same. 338 /// Eventually, we want to propagate storage locations from result objects 339 /// down to the prvalues that initialize them, similar to the way that this is 340 /// done in Clang's CodeGen. 341 /// 342 /// Requirements: 343 /// `E` must be a prvalue of record type. 344 RecordStorageLocation & 345 getResultObjectLocation(const Expr &RecordPRValue) const; 346 347 /// Returns the return value of the current function. This can be null if: 348 /// - The function has a void return type 349 /// - No return value could be determined for the function, for example 350 /// because it calls a function without a body. 351 /// 352 /// Requirements: 353 /// The current function must have a non-reference return type. 354 Value *getReturnValue() const { 355 assert(getCurrentFunc() != nullptr && 356 !getCurrentFunc()->getReturnType()->isReferenceType()); 357 return ReturnVal; 358 } 359 360 /// Returns the storage location for the reference returned by the current 361 /// function. This can be null if function doesn't return a single consistent 362 /// reference. 363 /// 364 /// Requirements: 365 /// The current function must have a reference return type. 366 StorageLocation *getReturnStorageLocation() const { 367 assert(getCurrentFunc() != nullptr && 368 getCurrentFunc()->getReturnType()->isReferenceType()); 369 return ReturnLoc; 370 } 371 372 /// Sets the return value of the current function. 373 /// 374 /// Requirements: 375 /// The current function must have a non-reference return type. 376 void setReturnValue(Value *Val) { 377 assert(getCurrentFunc() != nullptr && 378 !getCurrentFunc()->getReturnType()->isReferenceType()); 379 ReturnVal = Val; 380 } 381 382 /// Sets the storage location for the reference returned by the current 383 /// function. 384 /// 385 /// Requirements: 386 /// The current function must have a reference return type. 387 void setReturnStorageLocation(StorageLocation *Loc) { 388 assert(getCurrentFunc() != nullptr && 389 getCurrentFunc()->getReturnType()->isReferenceType()); 390 ReturnLoc = Loc; 391 } 392 393 /// Returns a pointer value that represents a null pointer. Calls with 394 /// `PointeeType` that are canonically equivalent will return the same result. 395 PointerValue &getOrCreateNullPointerValue(QualType PointeeType); 396 397 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 398 /// returns null. 399 /// 400 /// If `Type` is a pointer or reference type, creates all the necessary 401 /// storage locations and values for indirections until it finds a 402 /// non-pointer/non-reference type. 403 /// 404 /// If `Type` is a class, struct, or union type, creates values for all 405 /// modeled fields (including synthetic fields) and calls `setValue()` to 406 /// associate the `RecordValue` with its storage location 407 /// (`RecordValue::getLoc()`). 408 /// 409 /// If `Type` is one of the following types, this function will always return 410 /// a non-null pointer: 411 /// - `bool` 412 /// - Any integer type 413 /// - Any class, struct, or union type 414 /// 415 /// Requirements: 416 /// 417 /// `Type` must not be null. 418 Value *createValue(QualType Type); 419 420 /// Creates an object (i.e. a storage location with an associated value) of 421 /// type `Ty`. If `InitExpr` is non-null and has a value associated with it, 422 /// initializes the object with this value. Otherwise, initializes the object 423 /// with a value created using `createValue()`. 424 StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) { 425 return createObjectInternal(nullptr, Ty, InitExpr); 426 } 427 428 /// Creates an object for the variable declaration `D`. If `D` has an 429 /// initializer and this initializer is associated with a value, initializes 430 /// the object with this value. Otherwise, initializes the object with a 431 /// value created using `createValue()`. Uses the storage location returned by 432 /// `DataflowAnalysisContext::getStableStorageLocation(D)`. 433 StorageLocation &createObject(const VarDecl &D) { 434 return createObjectInternal(&D, D.getType(), D.getInit()); 435 } 436 437 /// Creates an object for the variable declaration `D`. If `InitExpr` is 438 /// non-null and has a value associated with it, initializes the object with 439 /// this value. Otherwise, initializes the object with a value created using 440 /// `createValue()`. Uses the storage location returned by 441 /// `DataflowAnalysisContext::getStableStorageLocation(D)`. 442 StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) { 443 return createObjectInternal(&D, D.getType(), InitExpr); 444 } 445 446 /// Assigns `Val` as the value of `Loc` in the environment. 447 void setValue(const StorageLocation &Loc, Value &Val); 448 449 /// Clears any association between `Loc` and a value in the environment. 450 void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); } 451 452 /// Assigns `Val` as the value of the prvalue `E` in the environment. 453 /// 454 /// Requirements: 455 /// 456 /// - `E` must be a prvalue 457 /// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be 458 /// `getResultObjectLocation(E)`. An exception to this is if `E` is an 459 /// expression that originally creates a `RecordValue` (such as a 460 /// `CXXConstructExpr` or `CallExpr`), as these establish the location of 461 /// the result object in the first place. 462 void setValue(const Expr &E, Value &Val); 463 464 /// Returns the value assigned to `Loc` in the environment or null if `Loc` 465 /// isn't assigned a value in the environment. 466 Value *getValue(const StorageLocation &Loc) const; 467 468 /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a 469 /// storage location in the environment, otherwise returns null. 470 Value *getValue(const ValueDecl &D) const; 471 472 /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a 473 /// storage location in the environment, otherwise returns null. 474 Value *getValue(const Expr &E) const; 475 476 /// Returns the result of casting `getValue(...)` to a subclass of `Value` 477 /// (using `cast_or_null<T>`). 478 /// This assert-fails if the result of `getValue(...)` is not of type `T *`; 479 /// if the value is not guaranteed to have type `T *`, consider using 480 /// `dyn_cast_or_null<T>(getValue(...))` instead. 481 template <typename T> 482 std::enable_if_t<std::is_base_of_v<Value, T>, T *> 483 get(const StorageLocation &Loc) const { 484 return cast_or_null<T>(getValue(Loc)); 485 } 486 template <typename T> 487 std::enable_if_t<std::is_base_of_v<Value, T>, T *> 488 get(const ValueDecl &D) const { 489 return cast_or_null<T>(getValue(D)); 490 } 491 template <typename T> 492 std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const { 493 return cast_or_null<T>(getValue(E)); 494 } 495 496 // FIXME: should we deprecate the following & call arena().create() directly? 497 498 /// Creates a `T` (some subclass of `Value`), forwarding `args` to the 499 /// constructor, and returns a reference to it. 500 /// 501 /// The analysis context takes ownership of the created object. The object 502 /// will be destroyed when the analysis context is destroyed. 503 template <typename T, typename... Args> 504 std::enable_if_t<std::is_base_of<Value, T>::value, T &> 505 create(Args &&...args) { 506 return arena().create<T>(std::forward<Args>(args)...); 507 } 508 509 /// Returns a symbolic integer value that models an integer literal equal to 510 /// `Value` 511 IntegerValue &getIntLiteralValue(llvm::APInt Value) const { 512 return arena().makeIntLiteral(Value); 513 } 514 515 /// Returns a symbolic boolean value that models a boolean literal equal to 516 /// `Value` 517 BoolValue &getBoolLiteralValue(bool Value) const { 518 return arena().makeBoolValue(arena().makeLiteral(Value)); 519 } 520 521 /// Returns an atomic boolean value. 522 BoolValue &makeAtomicBoolValue() const { 523 return arena().makeAtomValue(); 524 } 525 526 /// Returns a unique instance of boolean Top. 527 BoolValue &makeTopBoolValue() const { 528 return arena().makeTopValue(); 529 } 530 531 /// Returns a boolean value that represents the conjunction of `LHS` and 532 /// `RHS`. Subsequent calls with the same arguments, regardless of their 533 /// order, will return the same result. If the given boolean values represent 534 /// the same value, the result will be the value itself. 535 BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const { 536 return arena().makeBoolValue( 537 arena().makeAnd(LHS.formula(), RHS.formula())); 538 } 539 540 /// Returns a boolean value that represents the disjunction of `LHS` and 541 /// `RHS`. Subsequent calls with the same arguments, regardless of their 542 /// order, will return the same result. If the given boolean values represent 543 /// the same value, the result will be the value itself. 544 BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const { 545 return arena().makeBoolValue( 546 arena().makeOr(LHS.formula(), RHS.formula())); 547 } 548 549 /// Returns a boolean value that represents the negation of `Val`. Subsequent 550 /// calls with the same argument will return the same result. 551 BoolValue &makeNot(BoolValue &Val) const { 552 return arena().makeBoolValue(arena().makeNot(Val.formula())); 553 } 554 555 /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with 556 /// the same arguments, will return the same result. If the given boolean 557 /// values represent the same value, the result will be a value that 558 /// represents the true boolean literal. 559 BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const { 560 return arena().makeBoolValue( 561 arena().makeImplies(LHS.formula(), RHS.formula())); 562 } 563 564 /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with 565 /// the same arguments, regardless of their order, will return the same 566 /// result. If the given boolean values represent the same value, the result 567 /// will be a value that represents the true boolean literal. 568 BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const { 569 return arena().makeBoolValue( 570 arena().makeEquals(LHS.formula(), RHS.formula())); 571 } 572 573 /// Returns a boolean variable that identifies the flow condition (FC). 574 /// 575 /// The flow condition is a set of facts that are necessarily true when the 576 /// program reaches the current point, expressed as boolean formulas. 577 /// The flow condition token is equivalent to the AND of these facts. 578 /// 579 /// These may e.g. constrain the value of certain variables. A pointer 580 /// variable may have a consistent modeled PointerValue throughout, but at a 581 /// given point the Environment may tell us that the value must be non-null. 582 /// 583 /// The FC is necessary but not sufficient for this point to be reachable. 584 /// In particular, where the FC token appears in flow conditions of successor 585 /// environments, it means "point X may have been reached", not 586 /// "point X was reached". 587 Atom getFlowConditionToken() const { return FlowConditionToken; } 588 589 /// Record a fact that must be true if this point in the program is reached. 590 void assume(const Formula &); 591 592 /// Returns true if the formula is always true when this point is reached. 593 /// Returns false if the formula may be false (or the flow condition isn't 594 /// sufficiently precise to prove that it is true) or if the solver times out. 595 /// 596 /// Note that there is an asymmetry between this function and `allows()` in 597 /// that they both return false if the solver times out. The assumption is 598 /// that if `proves()` or `allows()` returns true, this will result in a 599 /// diagnostic, and we want to bias towards false negatives in the case where 600 /// the solver times out. 601 bool proves(const Formula &) const; 602 603 /// Returns true if the formula may be true when this point is reached. 604 /// Returns false if the formula is always false when this point is reached 605 /// (or the flow condition is overly constraining) or if the solver times out. 606 bool allows(const Formula &) const; 607 608 /// Returns the `DeclContext` of the block being analysed, if any. Otherwise, 609 /// returns null. 610 const DeclContext *getDeclCtx() const { return CallStack.back(); } 611 612 /// Returns the function currently being analyzed, or null if the code being 613 /// analyzed isn't part of a function. 614 const FunctionDecl *getCurrentFunc() const { 615 return dyn_cast<FunctionDecl>(getDeclCtx()); 616 } 617 618 /// Returns the size of the call stack. 619 size_t callStackSize() const { return CallStack.size(); } 620 621 /// Returns whether this `Environment` can be extended to analyze the given 622 /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a 623 /// given `MaxDepth`. 624 bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const; 625 626 /// Returns the `DataflowAnalysisContext` used by the environment. 627 DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; } 628 629 Arena &arena() const { return DACtx->arena(); } 630 631 LLVM_DUMP_METHOD void dump() const; 632 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; 633 634 private: 635 // The copy-constructor is for use in fork() only. 636 Environment(const Environment &) = default; 637 638 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 639 /// return null. 640 /// 641 /// Recursively initializes storage locations and values until it sees a 642 /// self-referential pointer or reference type. `Visited` is used to track 643 /// which types appeared in the reference/pointer chain in order to avoid 644 /// creating a cyclic dependency with self-referential pointers/references. 645 /// 646 /// Requirements: 647 /// 648 /// `Type` must not be null. 649 Value *createValueUnlessSelfReferential(QualType Type, 650 llvm::DenseSet<QualType> &Visited, 651 int Depth, int &CreatedValuesCount); 652 653 /// Creates a storage location for `Ty`. Also creates and associates a value 654 /// with the storage location, unless values of this type are not supported or 655 /// we hit one of the limits at which we stop producing values (controlled by 656 /// `Visited`, `Depth`, and `CreatedValuesCount`). 657 StorageLocation &createLocAndMaybeValue(QualType Ty, 658 llvm::DenseSet<QualType> &Visited, 659 int Depth, int &CreatedValuesCount); 660 661 /// Shared implementation of `createObject()` overloads. 662 /// `D` and `InitExpr` may be null. 663 StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty, 664 const Expr *InitExpr); 665 666 /// Shared implementation of `pushCall` overloads. Note that unlike 667 /// `pushCall`, this member is invoked on the environment of the callee, not 668 /// of the caller. 669 void pushCallInternal(const FunctionDecl *FuncDecl, 670 ArrayRef<const Expr *> Args); 671 672 /// Assigns storage locations and values to all global variables, fields 673 /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body. 674 void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl); 675 676 // `DACtx` is not null and not owned by this object. 677 DataflowAnalysisContext *DACtx; 678 679 // FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and 680 // `ThisPointeeLoc` into a separate call-context object, shared between 681 // environments in the same call. 682 // https://github.com/llvm/llvm-project/issues/59005 683 684 // `DeclContext` of the block being analysed if provided. 685 std::vector<const DeclContext *> CallStack; 686 687 // Value returned by the function (if it has non-reference return type). 688 Value *ReturnVal = nullptr; 689 // Storage location of the reference returned by the function (if it has 690 // reference return type). 691 StorageLocation *ReturnLoc = nullptr; 692 // The storage location of the `this` pointee. Should only be null if the 693 // function being analyzed is only a function and not a method. 694 RecordStorageLocation *ThisPointeeLoc = nullptr; 695 696 // Maps from declarations and glvalue expression to storage locations that are 697 // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these 698 // include only storage locations that are in scope for a particular basic 699 // block. 700 llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; 701 llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; 702 // Maps from prvalue expressions and storage locations to the values that 703 // are assigned to them. 704 // We preserve insertion order so that join/widen process values in 705 // deterministic sequence. This in turn produces deterministic SAT formulas. 706 llvm::MapVector<const Expr *, Value *> ExprToVal; 707 llvm::MapVector<const StorageLocation *, Value *> LocToVal; 708 709 Atom FlowConditionToken; 710 }; 711 712 /// Returns the storage location for the implicit object of a 713 /// `CXXMemberCallExpr`, or null if none is defined in the environment. 714 /// Dereferences the pointer if the member call expression was written using 715 /// `->`. 716 RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 717 const Environment &Env); 718 719 /// Returns the storage location for the base object of a `MemberExpr`, or null 720 /// if none is defined in the environment. Dereferences the pointer if the 721 /// member expression was written using `->`. 722 RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 723 const Environment &Env); 724 725 /// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the 726 /// order in which they appear in `InitListExpr::inits()`. 727 std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD); 728 729 /// Associates a new `RecordValue` with `Loc` and returns the new value. 730 RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env); 731 732 /// Associates a new `RecordValue` with `Expr` and returns the new value. 733 RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env); 734 735 } // namespace dataflow 736 } // namespace clang 737 738 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 739