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