|
|
|||
File indexing completed on 2026-05-10 08:36:25
0001 //===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 // 0009 // This file defines an Environment class that is used by dataflow analyses 0010 // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 0011 // program at given program points. 0012 // 0013 //===----------------------------------------------------------------------===// 0014 0015 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 0016 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H 0017 0018 #include "clang/AST/Decl.h" 0019 #include "clang/AST/DeclBase.h" 0020 #include "clang/AST/Expr.h" 0021 #include "clang/AST/Type.h" 0022 #include "clang/Analysis/FlowSensitive/ASTOps.h" 0023 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 0024 #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 0025 #include "clang/Analysis/FlowSensitive/Formula.h" 0026 #include "clang/Analysis/FlowSensitive/Logger.h" 0027 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 0028 #include "clang/Analysis/FlowSensitive/Value.h" 0029 #include "llvm/ADT/DenseMap.h" 0030 #include "llvm/ADT/DenseSet.h" 0031 #include "llvm/ADT/MapVector.h" 0032 #include "llvm/Support/Compiler.h" 0033 #include "llvm/Support/ErrorHandling.h" 0034 #include <cassert> 0035 #include <memory> 0036 #include <type_traits> 0037 #include <utility> 0038 #include <vector> 0039 0040 namespace clang { 0041 namespace dataflow { 0042 0043 /// Indicates the result of a tentative comparison. 0044 enum class ComparisonResult { 0045 Same, 0046 Different, 0047 Unknown, 0048 }; 0049 0050 /// The result of a `widen` operation. 0051 struct WidenResult { 0052 /// Non-null pointer to a potentially widened version of the input value. 0053 Value *V; 0054 /// Whether `V` represents a "change" (that is, a different value) with 0055 /// respect to the previous value in the sequence. 0056 LatticeEffect Effect; 0057 }; 0058 0059 /// Holds the state of the program (store and heap) at a given program point. 0060 /// 0061 /// WARNING: Symbolic values that are created by the environment for static 0062 /// local and global variables are not currently invalidated on function calls. 0063 /// This is unsound and should be taken into account when designing dataflow 0064 /// analyses. 0065 class Environment { 0066 public: 0067 /// Supplements `Environment` with non-standard comparison and join 0068 /// operations. 0069 class ValueModel { 0070 public: 0071 virtual ~ValueModel() = default; 0072 0073 /// Returns: 0074 /// `Same`: `Val1` is equivalent to `Val2`, according to the model. 0075 /// `Different`: `Val1` is distinct from `Val2`, according to the model. 0076 /// `Unknown`: The model can't determine a relationship between `Val1` and 0077 /// `Val2`. 0078 /// 0079 /// Requirements: 0080 /// 0081 /// `Val1` and `Val2` must be distinct. 0082 /// 0083 /// `Val1` and `Val2` must model values of type `Type`. 0084 /// 0085 /// `Val1` and `Val2` must be assigned to the same storage location in 0086 /// `Env1` and `Env2` respectively. 0087 virtual ComparisonResult compare(QualType Type, const Value &Val1, 0088 const Environment &Env1, const Value &Val2, 0089 const Environment &Env2) { 0090 // FIXME: Consider adding `QualType` to `Value` and removing the `Type` 0091 // argument here. 0092 return ComparisonResult::Unknown; 0093 } 0094 0095 /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should 0096 /// obey the properties of a lattice join. 0097 /// 0098 /// `Env1` and `Env2` can be used to query child values and path condition 0099 /// implications of `Val1` and `Val2` respectively. 0100 /// 0101 /// Requirements: 0102 /// 0103 /// `Val1` and `Val2` must be distinct. 0104 /// 0105 /// `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`. 0106 /// 0107 /// `Val1` and `Val2` must be assigned to the same storage location in 0108 /// `Env1` and `Env2` respectively. 0109 virtual void join(QualType Type, const Value &Val1, const Environment &Env1, 0110 const Value &Val2, const Environment &Env2, 0111 Value &JoinedVal, Environment &JoinedEnv) {} 0112 0113 /// This function may widen the current value -- replace it with an 0114 /// approximation that can reach a fixed point more quickly than iterated 0115 /// application of the transfer function alone. The previous value is 0116 /// provided to inform the choice of widened value. The function must also 0117 /// serve as a comparison operation, by indicating whether the widened value 0118 /// is equivalent to the previous value. 0119 /// 0120 /// Returns one of the folowing: 0121 /// * `std::nullopt`, if this value is not of interest to the 0122 /// model. 0123 /// * A `WidenResult` with: 0124 /// * A non-null `Value *` that points either to `Current` or a widened 0125 /// version of `Current`. This value must be consistent with 0126 /// the flow condition of `CurrentEnv`. We particularly caution 0127 /// against using `Prev`, which is rarely consistent. 0128 /// * A `LatticeEffect` indicating whether the value should be 0129 /// considered a new value (`Changed`) or one *equivalent* (if not 0130 /// necessarily equal) to `Prev` (`Unchanged`). 0131 /// 0132 /// `PrevEnv` and `CurrentEnv` can be used to query child values and path 0133 /// condition implications of `Prev` and `Current`, respectively. 0134 /// 0135 /// Requirements: 0136 /// 0137 /// `Prev` and `Current` must model values of type `Type`. 0138 /// 0139 /// `Prev` and `Current` must be assigned to the same storage location in 0140 /// `PrevEnv` and `CurrentEnv`, respectively. 0141 virtual std::optional<WidenResult> widen(QualType Type, Value &Prev, 0142 const Environment &PrevEnv, 0143 Value &Current, 0144 Environment &CurrentEnv) { 0145 // The default implementation reduces to just comparison, since comparison 0146 // is required by the API, even if no widening is performed. 0147 switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { 0148 case ComparisonResult::Unknown: 0149 return std::nullopt; 0150 case ComparisonResult::Same: 0151 return WidenResult{&Current, LatticeEffect::Unchanged}; 0152 case ComparisonResult::Different: 0153 return WidenResult{&Current, LatticeEffect::Changed}; 0154 } 0155 llvm_unreachable("all cases in switch covered"); 0156 } 0157 }; 0158 0159 /// Creates an environment that uses `DACtx` to store objects that encompass 0160 /// the state of a program. 0161 explicit Environment(DataflowAnalysisContext &DACtx) 0162 : DACtx(&DACtx), 0163 FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} 0164 0165 /// Creates an environment that uses `DACtx` to store objects that encompass 0166 /// the state of a program, with `S` as the statement to analyze. 0167 Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) { 0168 InitialTargetStmt = &S; 0169 } 0170 0171 /// Creates an environment that uses `DACtx` to store objects that encompass 0172 /// the state of a program, with `FD` as the function to analyze. 0173 /// 0174 /// Requirements: 0175 /// 0176 /// The function must have a body, i.e. 0177 /// `FunctionDecl::doesThisDecalarationHaveABody()` must be true. 0178 Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD) 0179 : Environment(DACtx, *FD.getBody()) { 0180 assert(FD.doesThisDeclarationHaveABody()); 0181 InitialTargetFunc = &FD; 0182 } 0183 0184 // Copy-constructor is private, Environments should not be copied. See fork(). 0185 Environment &operator=(const Environment &Other) = delete; 0186 0187 Environment(Environment &&Other) = default; 0188 Environment &operator=(Environment &&Other) = default; 0189 0190 /// Assigns storage locations and values to all parameters, captures, global 0191 /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl` 0192 /// passed to the constructor. 0193 /// 0194 /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing. 0195 void initialize(); 0196 0197 /// Returns a new environment that is a copy of this one. 0198 /// 0199 /// The state of the program is initially the same, but can be mutated without 0200 /// affecting the original. 0201 /// 0202 /// However the original should not be further mutated, as this may interfere 0203 /// with the fork. (In practice, values are stored independently, but the 0204 /// forked flow condition references the original). 0205 Environment fork() const; 0206 0207 /// Creates and returns an environment to use for an inline analysis of the 0208 /// callee. Uses the storage location from each argument in the `Call` as the 0209 /// storage location for the corresponding parameter in the callee. 0210 /// 0211 /// Requirements: 0212 /// 0213 /// The callee of `Call` must be a `FunctionDecl`. 0214 /// 0215 /// The body of the callee must not reference globals. 0216 /// 0217 /// The arguments of `Call` must map 1:1 to the callee's parameters. 0218 Environment pushCall(const CallExpr *Call) const; 0219 Environment pushCall(const CXXConstructExpr *Call) const; 0220 0221 /// Moves gathered information back into `this` from a `CalleeEnv` created via 0222 /// `pushCall`. 0223 void popCall(const CallExpr *Call, const Environment &CalleeEnv); 0224 void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv); 0225 0226 /// Returns true if and only if the environment is equivalent to `Other`, i.e 0227 /// the two environments: 0228 /// - have the same mappings from declarations to storage locations, 0229 /// - have the same mappings from expressions to storage locations, 0230 /// - have the same or equivalent (according to `Model`) values assigned to 0231 /// the same storage locations. 0232 /// 0233 /// Requirements: 0234 /// 0235 /// `Other` and `this` must use the same `DataflowAnalysisContext`. 0236 bool equivalentTo(const Environment &Other, 0237 Environment::ValueModel &Model) const; 0238 0239 /// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join. 0240 /// If the join happens within a full expression, expression state should be 0241 /// kept; otherwise, we can discard it. 0242 enum ExprJoinBehavior { 0243 DiscardExprState, 0244 KeepExprState, 0245 }; 0246 0247 /// Joins two environments by taking the intersection of storage locations and 0248 /// values that are stored in them. Distinct values that are assigned to the 0249 /// same storage locations in `EnvA` and `EnvB` are merged using `Model`. 0250 /// 0251 /// Requirements: 0252 /// 0253 /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`. 0254 static Environment join(const Environment &EnvA, const Environment &EnvB, 0255 Environment::ValueModel &Model, 0256 ExprJoinBehavior ExprBehavior); 0257 0258 /// Returns a value that approximates both `Val1` and `Val2`, or null if no 0259 /// such value can be produced. 0260 /// 0261 /// `Env1` and `Env2` can be used to query child values and path condition 0262 /// implications of `Val1` and `Val2` respectively. The joined value will be 0263 /// produced in `JoinedEnv`. 0264 /// 0265 /// Requirements: 0266 /// 0267 /// `Val1` and `Val2` must model values of type `Type`. 0268 static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1, 0269 Value *Val2, const Environment &Env2, 0270 Environment &JoinedEnv, 0271 Environment::ValueModel &Model); 0272 0273 /// Widens the environment point-wise, using `PrevEnv` as needed to inform the 0274 /// approximation. 0275 /// 0276 /// Requirements: 0277 /// 0278 /// `PrevEnv` must be the immediate previous version of the environment. 0279 /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. 0280 LatticeEffect widen(const Environment &PrevEnv, 0281 Environment::ValueModel &Model); 0282 0283 // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, 0284 // `getStableStorageLocation`, or something more appropriate. 0285 0286 /// Creates a storage location appropriate for `Type`. Does not assign a value 0287 /// to the returned storage location in the environment. 0288 /// 0289 /// Requirements: 0290 /// 0291 /// `Type` must not be null. 0292 StorageLocation &createStorageLocation(QualType Type); 0293 0294 /// Creates a storage location for `D`. Does not assign the returned storage 0295 /// location to `D` in the environment. Does not assign a value to the 0296 /// returned storage location in the environment. 0297 StorageLocation &createStorageLocation(const ValueDecl &D); 0298 0299 /// Creates a storage location for `E`. Does not assign the returned storage 0300 /// location to `E` in the environment. Does not assign a value to the 0301 /// returned storage location in the environment. 0302 StorageLocation &createStorageLocation(const Expr &E); 0303 0304 /// Assigns `Loc` as the storage location of `D` in the environment. 0305 /// 0306 /// Requirements: 0307 /// 0308 /// `D` must not already have a storage location in the environment. 0309 void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); 0310 0311 /// Returns the storage location assigned to `D` in the environment, or null 0312 /// if `D` isn't assigned a storage location in the environment. 0313 StorageLocation *getStorageLocation(const ValueDecl &D) const; 0314 0315 /// Removes the location assigned to `D` in the environment (if any). 0316 void removeDecl(const ValueDecl &D); 0317 0318 /// Assigns `Loc` as the storage location of the glvalue `E` in the 0319 /// environment. 0320 /// 0321 /// Requirements: 0322 /// 0323 /// `E` must not be assigned a storage location in the environment. 0324 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 0325 void setStorageLocation(const Expr &E, StorageLocation &Loc); 0326 0327 /// Returns the storage location assigned to the glvalue `E` in the 0328 /// environment, or null if `E` isn't assigned a storage location in the 0329 /// environment. 0330 /// 0331 /// Requirements: 0332 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` 0333 StorageLocation *getStorageLocation(const Expr &E) const; 0334 0335 /// Returns the result of casting `getStorageLocation(...)` to a subclass of 0336 /// `StorageLocation` (using `cast_or_null<T>`). 0337 /// This assert-fails if the result of `getStorageLocation(...)` is not of 0338 /// type `T *`; if the storage location is not guaranteed to have type `T *`, 0339 /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead. 0340 template <typename T> 0341 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> 0342 get(const ValueDecl &D) const { 0343 return cast_or_null<T>(getStorageLocation(D)); 0344 } 0345 template <typename T> 0346 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *> 0347 get(const Expr &E) const { 0348 return cast_or_null<T>(getStorageLocation(E)); 0349 } 0350 0351 /// Returns the storage location assigned to the `this` pointee in the 0352 /// environment or null if the `this` pointee has no assigned storage location 0353 /// in the environment. 0354 RecordStorageLocation *getThisPointeeStorageLocation() const { 0355 return ThisPointeeLoc; 0356 } 0357 0358 /// Sets the storage location assigned to the `this` pointee in the 0359 /// environment. 0360 void setThisPointeeStorageLocation(RecordStorageLocation &Loc) { 0361 ThisPointeeLoc = &Loc; 0362 } 0363 0364 /// Returns the location of the result object for a record-type prvalue. 0365 /// 0366 /// In C++, prvalues of record type serve only a limited purpose: They can 0367 /// only be used to initialize a result object (e.g. a variable or a 0368 /// temporary). This function returns the location of that result object. 0369 /// 0370 /// When creating a prvalue of record type, we already need the storage 0371 /// location of the result object to pass in `this`, even though prvalues are 0372 /// otherwise not associated with storage locations. 0373 /// 0374 /// Requirements: 0375 /// `E` must be a prvalue of record type. 0376 RecordStorageLocation & 0377 getResultObjectLocation(const Expr &RecordPRValue) const; 0378 0379 /// Returns the return value of the function currently being analyzed. 0380 /// This can be null if: 0381 /// - The function has a void return type 0382 /// - No return value could be determined for the function, for example 0383 /// because it calls a function without a body. 0384 /// 0385 /// Requirements: 0386 /// The current analysis target must be a function and must have a 0387 /// non-reference return type. 0388 Value *getReturnValue() const { 0389 assert(getCurrentFunc() != nullptr && 0390 !getCurrentFunc()->getReturnType()->isReferenceType()); 0391 return ReturnVal; 0392 } 0393 0394 /// Returns the storage location for the reference returned by the function 0395 /// currently being analyzed. This can be null if the function doesn't return 0396 /// a single consistent reference. 0397 /// 0398 /// Requirements: 0399 /// The current analysis target must be a function and must have a reference 0400 /// return type. 0401 StorageLocation *getReturnStorageLocation() const { 0402 assert(getCurrentFunc() != nullptr && 0403 getCurrentFunc()->getReturnType()->isReferenceType()); 0404 return ReturnLoc; 0405 } 0406 0407 /// Sets the return value of the function currently being analyzed. 0408 /// 0409 /// Requirements: 0410 /// The current analysis target must be a function and must have a 0411 /// non-reference return type. 0412 void setReturnValue(Value *Val) { 0413 assert(getCurrentFunc() != nullptr && 0414 !getCurrentFunc()->getReturnType()->isReferenceType()); 0415 ReturnVal = Val; 0416 } 0417 0418 /// Sets the storage location for the reference returned by the function 0419 /// currently being analyzed. 0420 /// 0421 /// Requirements: 0422 /// The current analysis target must be a function and must have a reference 0423 /// return type. 0424 void setReturnStorageLocation(StorageLocation *Loc) { 0425 assert(getCurrentFunc() != nullptr && 0426 getCurrentFunc()->getReturnType()->isReferenceType()); 0427 ReturnLoc = Loc; 0428 } 0429 0430 /// Returns a pointer value that represents a null pointer. Calls with 0431 /// `PointeeType` that are canonically equivalent will return the same result. 0432 PointerValue &getOrCreateNullPointerValue(QualType PointeeType); 0433 0434 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 0435 /// returns null. 0436 /// 0437 /// If `Type` is a pointer or reference type, creates all the necessary 0438 /// storage locations and values for indirections until it finds a 0439 /// non-pointer/non-reference type. 0440 /// 0441 /// If `Type` is one of the following types, this function will always return 0442 /// a non-null pointer: 0443 /// - `bool` 0444 /// - Any integer type 0445 /// 0446 /// Requirements: 0447 /// 0448 /// - `Type` must not be null. 0449 /// - `Type` must not be a reference type or record type. 0450 Value *createValue(QualType Type); 0451 0452 /// Creates an object (i.e. a storage location with an associated value) of 0453 /// type `Ty`. If `InitExpr` is non-null and has a value associated with it, 0454 /// initializes the object with this value. Otherwise, initializes the object 0455 /// with a value created using `createValue()`. 0456 StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) { 0457 return createObjectInternal(nullptr, Ty, InitExpr); 0458 } 0459 0460 /// Creates an object for the variable declaration `D`. If `D` has an 0461 /// initializer and this initializer is associated with a value, initializes 0462 /// the object with this value. Otherwise, initializes the object with a 0463 /// value created using `createValue()`. Uses the storage location returned by 0464 /// `DataflowAnalysisContext::getStableStorageLocation(D)`. 0465 StorageLocation &createObject(const VarDecl &D) { 0466 return createObjectInternal(&D, D.getType(), D.getInit()); 0467 } 0468 0469 /// Creates an object for the variable declaration `D`. If `InitExpr` is 0470 /// non-null and has a value associated with it, initializes the object with 0471 /// this value. Otherwise, initializes the object with a value created using 0472 /// `createValue()`. Uses the storage location returned by 0473 /// `DataflowAnalysisContext::getStableStorageLocation(D)`. 0474 StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) { 0475 return createObjectInternal(&D, D.getType(), InitExpr); 0476 } 0477 0478 /// Initializes the fields (including synthetic fields) of `Loc` with values, 0479 /// unless values of the field type are not supported or we hit one of the 0480 /// limits at which we stop producing values. 0481 /// If a field already has a value, that value is preserved. 0482 /// If `Type` is provided, initializes only those fields that are modeled for 0483 /// `Type`; this is intended for use in cases where `Loc` is a derived type 0484 /// and we only want to initialize the fields of a base type. 0485 void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type); 0486 void initializeFieldsWithValues(RecordStorageLocation &Loc) { 0487 initializeFieldsWithValues(Loc, Loc.getType()); 0488 } 0489 0490 /// Assigns `Val` as the value of `Loc` in the environment. 0491 /// 0492 /// Requirements: 0493 /// 0494 /// `Loc` must not be a `RecordStorageLocation`. 0495 void setValue(const StorageLocation &Loc, Value &Val); 0496 0497 /// Clears any association between `Loc` and a value in the environment. 0498 void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); } 0499 0500 /// Assigns `Val` as the value of the prvalue `E` in the environment. 0501 /// 0502 /// Requirements: 0503 /// 0504 /// - `E` must be a prvalue. 0505 /// - `E` must not have record type. 0506 void setValue(const Expr &E, Value &Val); 0507 0508 /// Returns the value assigned to `Loc` in the environment or null if `Loc` 0509 /// isn't assigned a value in the environment. 0510 /// 0511 /// Requirements: 0512 /// 0513 /// `Loc` must not be a `RecordStorageLocation`. 0514 Value *getValue(const StorageLocation &Loc) const; 0515 0516 /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a 0517 /// storage location in the environment, otherwise returns null. 0518 /// 0519 /// Requirements: 0520 /// 0521 /// `D` must not have record type. 0522 Value *getValue(const ValueDecl &D) const; 0523 0524 /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a 0525 /// storage location in the environment, otherwise returns null. 0526 Value *getValue(const Expr &E) const; 0527 0528 /// Returns the result of casting `getValue(...)` to a subclass of `Value` 0529 /// (using `cast_or_null<T>`). 0530 /// This assert-fails if the result of `getValue(...)` is not of type `T *`; 0531 /// if the value is not guaranteed to have type `T *`, consider using 0532 /// `dyn_cast_or_null<T>(getValue(...))` instead. 0533 template <typename T> 0534 std::enable_if_t<std::is_base_of_v<Value, T>, T *> 0535 get(const StorageLocation &Loc) const { 0536 return cast_or_null<T>(getValue(Loc)); 0537 } 0538 template <typename T> 0539 std::enable_if_t<std::is_base_of_v<Value, T>, T *> 0540 get(const ValueDecl &D) const { 0541 return cast_or_null<T>(getValue(D)); 0542 } 0543 template <typename T> 0544 std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const { 0545 return cast_or_null<T>(getValue(E)); 0546 } 0547 0548 // FIXME: should we deprecate the following & call arena().create() directly? 0549 0550 /// Creates a `T` (some subclass of `Value`), forwarding `args` to the 0551 /// constructor, and returns a reference to it. 0552 /// 0553 /// The analysis context takes ownership of the created object. The object 0554 /// will be destroyed when the analysis context is destroyed. 0555 template <typename T, typename... Args> 0556 std::enable_if_t<std::is_base_of<Value, T>::value, T &> 0557 create(Args &&...args) { 0558 return arena().create<T>(std::forward<Args>(args)...); 0559 } 0560 0561 /// Returns a symbolic integer value that models an integer literal equal to 0562 /// `Value` 0563 IntegerValue &getIntLiteralValue(llvm::APInt Value) const { 0564 return arena().makeIntLiteral(Value); 0565 } 0566 0567 /// Returns a symbolic boolean value that models a boolean literal equal to 0568 /// `Value` 0569 BoolValue &getBoolLiteralValue(bool Value) const { 0570 return arena().makeBoolValue(arena().makeLiteral(Value)); 0571 } 0572 0573 /// Returns an atomic boolean value. 0574 BoolValue &makeAtomicBoolValue() const { 0575 return arena().makeAtomValue(); 0576 } 0577 0578 /// Returns a unique instance of boolean Top. 0579 BoolValue &makeTopBoolValue() const { 0580 return arena().makeTopValue(); 0581 } 0582 0583 /// Returns a boolean value that represents the conjunction of `LHS` and 0584 /// `RHS`. Subsequent calls with the same arguments, regardless of their 0585 /// order, will return the same result. If the given boolean values represent 0586 /// the same value, the result will be the value itself. 0587 BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const { 0588 return arena().makeBoolValue( 0589 arena().makeAnd(LHS.formula(), RHS.formula())); 0590 } 0591 0592 /// Returns a boolean value that represents the disjunction of `LHS` and 0593 /// `RHS`. Subsequent calls with the same arguments, regardless of their 0594 /// order, will return the same result. If the given boolean values represent 0595 /// the same value, the result will be the value itself. 0596 BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const { 0597 return arena().makeBoolValue( 0598 arena().makeOr(LHS.formula(), RHS.formula())); 0599 } 0600 0601 /// Returns a boolean value that represents the negation of `Val`. Subsequent 0602 /// calls with the same argument will return the same result. 0603 BoolValue &makeNot(BoolValue &Val) const { 0604 return arena().makeBoolValue(arena().makeNot(Val.formula())); 0605 } 0606 0607 /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with 0608 /// the same arguments, will return the same result. If the given boolean 0609 /// values represent the same value, the result will be a value that 0610 /// represents the true boolean literal. 0611 BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const { 0612 return arena().makeBoolValue( 0613 arena().makeImplies(LHS.formula(), RHS.formula())); 0614 } 0615 0616 /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with 0617 /// the same arguments, regardless of their order, will return the same 0618 /// result. If the given boolean values represent the same value, the result 0619 /// will be a value that represents the true boolean literal. 0620 BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const { 0621 return arena().makeBoolValue( 0622 arena().makeEquals(LHS.formula(), RHS.formula())); 0623 } 0624 0625 /// Returns a boolean variable that identifies the flow condition (FC). 0626 /// 0627 /// The flow condition is a set of facts that are necessarily true when the 0628 /// program reaches the current point, expressed as boolean formulas. 0629 /// The flow condition token is equivalent to the AND of these facts. 0630 /// 0631 /// These may e.g. constrain the value of certain variables. A pointer 0632 /// variable may have a consistent modeled PointerValue throughout, but at a 0633 /// given point the Environment may tell us that the value must be non-null. 0634 /// 0635 /// The FC is necessary but not sufficient for this point to be reachable. 0636 /// In particular, where the FC token appears in flow conditions of successor 0637 /// environments, it means "point X may have been reached", not 0638 /// "point X was reached". 0639 Atom getFlowConditionToken() const { return FlowConditionToken; } 0640 0641 /// Record a fact that must be true if this point in the program is reached. 0642 void assume(const Formula &); 0643 0644 /// Returns true if the formula is always true when this point is reached. 0645 /// Returns false if the formula may be false (or the flow condition isn't 0646 /// sufficiently precise to prove that it is true) or if the solver times out. 0647 /// 0648 /// Note that there is an asymmetry between this function and `allows()` in 0649 /// that they both return false if the solver times out. The assumption is 0650 /// that if `proves()` or `allows()` returns true, this will result in a 0651 /// diagnostic, and we want to bias towards false negatives in the case where 0652 /// the solver times out. 0653 bool proves(const Formula &) const; 0654 0655 /// Returns true if the formula may be true when this point is reached. 0656 /// Returns false if the formula is always false when this point is reached 0657 /// (or the flow condition is overly constraining) or if the solver times out. 0658 bool allows(const Formula &) const; 0659 0660 /// Returns the function currently being analyzed, or null if the code being 0661 /// analyzed isn't part of a function. 0662 const FunctionDecl *getCurrentFunc() const { 0663 return CallStack.empty() ? InitialTargetFunc : CallStack.back(); 0664 } 0665 0666 /// Returns the size of the call stack, not counting the initial analysis 0667 /// target. 0668 size_t callStackSize() const { return CallStack.size(); } 0669 0670 /// Returns whether this `Environment` can be extended to analyze the given 0671 /// `Callee` (i.e. if `pushCall` can be used). 0672 /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack 0673 /// (i.e. the maximum value that `callStackSize()` may assume after the call). 0674 bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const; 0675 0676 /// Returns the `DataflowAnalysisContext` used by the environment. 0677 DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; } 0678 0679 Arena &arena() const { return DACtx->arena(); } 0680 0681 LLVM_DUMP_METHOD void dump() const; 0682 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; 0683 0684 private: 0685 using PrValueToResultObject = 0686 llvm::DenseMap<const Expr *, RecordStorageLocation *>; 0687 0688 // The copy-constructor is for use in fork() only. 0689 Environment(const Environment &) = default; 0690 0691 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise 0692 /// return null. 0693 /// 0694 /// Recursively initializes storage locations and values until it sees a 0695 /// self-referential pointer or reference type. `Visited` is used to track 0696 /// which types appeared in the reference/pointer chain in order to avoid 0697 /// creating a cyclic dependency with self-referential pointers/references. 0698 /// 0699 /// Requirements: 0700 /// 0701 /// `Type` must not be null. 0702 Value *createValueUnlessSelfReferential(QualType Type, 0703 llvm::DenseSet<QualType> &Visited, 0704 int Depth, int &CreatedValuesCount); 0705 0706 /// Creates a storage location for `Ty`. Also creates and associates a value 0707 /// with the storage location, unless values of this type are not supported or 0708 /// we hit one of the limits at which we stop producing values (controlled by 0709 /// `Visited`, `Depth`, and `CreatedValuesCount`). 0710 StorageLocation &createLocAndMaybeValue(QualType Ty, 0711 llvm::DenseSet<QualType> &Visited, 0712 int Depth, int &CreatedValuesCount); 0713 0714 /// Initializes the fields (including synthetic fields) of `Loc` with values, 0715 /// unless values of the field type are not supported or we hit one of the 0716 /// limits at which we stop producing values (controlled by `Visited`, 0717 /// `Depth`, and `CreatedValuesCount`). If `Type` is different from 0718 /// `Loc.getType()`, initializes only those fields that are modeled for 0719 /// `Type`. 0720 void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type, 0721 llvm::DenseSet<QualType> &Visited, int Depth, 0722 int &CreatedValuesCount); 0723 0724 /// Shared implementation of `createObject()` overloads. 0725 /// `D` and `InitExpr` may be null. 0726 StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty, 0727 const Expr *InitExpr); 0728 0729 /// Shared implementation of `pushCall` overloads. Note that unlike 0730 /// `pushCall`, this member is invoked on the environment of the callee, not 0731 /// of the caller. 0732 void pushCallInternal(const FunctionDecl *FuncDecl, 0733 ArrayRef<const Expr *> Args); 0734 0735 /// Assigns storage locations and values to all global variables, fields 0736 /// and functions in `Referenced`. 0737 void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced); 0738 0739 static PrValueToResultObject 0740 buildResultObjectMap(DataflowAnalysisContext *DACtx, 0741 const FunctionDecl *FuncDecl, 0742 RecordStorageLocation *ThisPointeeLoc, 0743 RecordStorageLocation *LocForRecordReturnVal); 0744 0745 static PrValueToResultObject 0746 buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S, 0747 RecordStorageLocation *ThisPointeeLoc, 0748 RecordStorageLocation *LocForRecordReturnVal); 0749 0750 // `DACtx` is not null and not owned by this object. 0751 DataflowAnalysisContext *DACtx; 0752 0753 // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`, 0754 // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object, 0755 // shared between environments in the same call. 0756 // https://github.com/llvm/llvm-project/issues/59005 0757 0758 // The stack of functions called from the initial analysis target. 0759 std::vector<const FunctionDecl *> CallStack; 0760 0761 // Initial function to analyze, if a function was passed to the constructor. 0762 // Null otherwise. 0763 const FunctionDecl *InitialTargetFunc = nullptr; 0764 // Top-level statement of the initial analysis target. 0765 // If a function was passed to the constructor, this is its body. 0766 // If a statement was passed to the constructor, this is that statement. 0767 // Null if no analysis target was passed to the constructor. 0768 Stmt *InitialTargetStmt = nullptr; 0769 0770 // Maps from prvalues of record type to their result objects. Shared between 0771 // all environments for the same analysis target. 0772 // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr` 0773 // here, though the cost is acceptable: The overhead of a `shared_ptr` is 0774 // incurred when it is copied, and this happens only relatively rarely (when 0775 // we fork the environment). The need for a `shared_ptr` will go away once we 0776 // introduce a shared call-context object (see above). 0777 std::shared_ptr<PrValueToResultObject> ResultObjectMap; 0778 0779 // The following three member variables handle various different types of 0780 // return values when the current analysis target is a function. 0781 // - If the return type is not a reference and not a record: Value returned 0782 // by the function. 0783 Value *ReturnVal = nullptr; 0784 // - If the return type is a reference: Storage location of the reference 0785 // returned by the function. 0786 StorageLocation *ReturnLoc = nullptr; 0787 // - If the return type is a record or the function being analyzed is a 0788 // constructor: Storage location into which the return value should be 0789 // constructed. 0790 RecordStorageLocation *LocForRecordReturnVal = nullptr; 0791 0792 // The storage location of the `this` pointee. Should only be null if the 0793 // analysis target is not a method. 0794 RecordStorageLocation *ThisPointeeLoc = nullptr; 0795 0796 // Maps from declarations and glvalue expression to storage locations that are 0797 // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these 0798 // include only storage locations that are in scope for a particular basic 0799 // block. 0800 llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; 0801 llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; 0802 // Maps from prvalue expressions and storage locations to the values that 0803 // are assigned to them. 0804 // We preserve insertion order so that join/widen process values in 0805 // deterministic sequence. This in turn produces deterministic SAT formulas. 0806 llvm::MapVector<const Expr *, Value *> ExprToVal; 0807 llvm::MapVector<const StorageLocation *, Value *> LocToVal; 0808 0809 Atom FlowConditionToken; 0810 }; 0811 0812 /// Returns the storage location for the implicit object of a 0813 /// `CXXMemberCallExpr`, or null if none is defined in the environment. 0814 /// Dereferences the pointer if the member call expression was written using 0815 /// `->`. 0816 RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 0817 const Environment &Env); 0818 0819 /// Returns the storage location for the base object of a `MemberExpr`, or null 0820 /// if none is defined in the environment. Dereferences the pointer if the 0821 /// member expression was written using `->`. 0822 RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 0823 const Environment &Env); 0824 0825 } // namespace dataflow 0826 } // namespace clang 0827 0828 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|