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