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