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