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