DataflowEnvironment.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines an Environment class that is used by dataflow analyses
  15. // that run over Control-Flow Graphs (CFGs) to keep track of the state of the
  16. // program at given program points.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
  20. #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
  21. #include "clang/AST/Decl.h"
  22. #include "clang/AST/DeclBase.h"
  23. #include "clang/AST/Expr.h"
  24. #include "clang/AST/Type.h"
  25. #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
  26. #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
  27. #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
  28. #include "clang/Analysis/FlowSensitive/StorageLocation.h"
  29. #include "clang/Analysis/FlowSensitive/Value.h"
  30. #include "llvm/ADT/DenseMap.h"
  31. #include "llvm/ADT/DenseSet.h"
  32. #include "llvm/Support/ErrorHandling.h"
  33. #include <memory>
  34. #include <type_traits>
  35. #include <utility>
  36. namespace clang {
  37. namespace dataflow {
  38. /// Indicates what kind of indirections should be skipped past when retrieving
  39. /// storage locations or values.
  40. ///
  41. /// FIXME: Consider renaming this or replacing it with a more appropriate model.
  42. /// See the discussion in https://reviews.llvm.org/D116596 for context.
  43. enum class SkipPast {
  44. /// No indirections should be skipped past.
  45. None,
  46. /// An optional reference should be skipped past.
  47. Reference,
  48. /// An optional reference should be skipped past, then an optional pointer
  49. /// should be skipped past.
  50. ReferenceThenPointer,
  51. };
  52. /// Indicates the result of a tentative comparison.
  53. enum class ComparisonResult {
  54. Same,
  55. Different,
  56. Unknown,
  57. };
  58. /// Holds the state of the program (store and heap) at a given program point.
  59. ///
  60. /// WARNING: Symbolic values that are created by the environment for static
  61. /// local and global variables are not currently invalidated on function calls.
  62. /// This is unsound and should be taken into account when designing dataflow
  63. /// analyses.
  64. class Environment {
  65. public:
  66. /// Supplements `Environment` with non-standard comparison and join
  67. /// operations.
  68. class ValueModel {
  69. public:
  70. virtual ~ValueModel() = default;
  71. /// Returns:
  72. /// `Same`: `Val1` is equivalent to `Val2`, according to the model.
  73. /// `Different`: `Val1` is distinct from `Val2`, according to the model.
  74. /// `Unknown`: The model can't determine a relationship between `Val1` and
  75. /// `Val2`.
  76. ///
  77. /// Requirements:
  78. ///
  79. /// `Val1` and `Val2` must be distinct.
  80. ///
  81. /// `Val1` and `Val2` must model values of type `Type`.
  82. ///
  83. /// `Val1` and `Val2` must be assigned to the same storage location in
  84. /// `Env1` and `Env2` respectively.
  85. virtual ComparisonResult compare(QualType Type, const Value &Val1,
  86. const Environment &Env1, const Value &Val2,
  87. const Environment &Env2) {
  88. // FIXME: Consider adding QualType to StructValue and removing the Type
  89. // argument here.
  90. return ComparisonResult::Unknown;
  91. }
  92. /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could
  93. /// be a strict lattice join or a more general widening operation.
  94. ///
  95. /// If this function returns true, `MergedVal` will be assigned to a storage
  96. /// location of type `Type` in `MergedEnv`.
  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 `MergedVal` 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.
  109. virtual bool merge(QualType Type, const Value &Val1,
  110. const Environment &Env1, const Value &Val2,
  111. const Environment &Env2, Value &MergedVal,
  112. Environment &MergedEnv) {
  113. return true;
  114. }
  115. /// This function may widen the current value -- replace it with an
  116. /// approximation that can reach a fixed point more quickly than iterated
  117. /// application of the transfer function alone. The previous value is
  118. /// provided to inform the choice of widened value. The function must also
  119. /// serve as a comparison operation, by indicating whether the widened value
  120. /// is equivalent to the previous value.
  121. ///
  122. /// Returns either:
  123. ///
  124. /// `nullptr`, if this value is not of interest to the model, or
  125. ///
  126. /// `&Prev`, if the widened value is equivalent to `Prev`, or
  127. ///
  128. /// A non-null value that approximates `Current`. `Prev` is available to
  129. /// inform the chosen approximation.
  130. ///
  131. /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
  132. /// condition implications of `Prev` and `Current`, respectively.
  133. ///
  134. /// Requirements:
  135. ///
  136. /// `Prev` and `Current` must model values of type `Type`.
  137. ///
  138. /// `Prev` and `Current` must be assigned to the same storage location in
  139. /// `PrevEnv` and `CurrentEnv`, respectively.
  140. virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
  141. Value &Current, 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::Same:
  146. return &Prev;
  147. case ComparisonResult::Different:
  148. return &Current;
  149. case ComparisonResult::Unknown:
  150. return nullptr;
  151. }
  152. llvm_unreachable("all cases in switch covered");
  153. }
  154. };
  155. /// Creates an environment that uses `DACtx` to store objects that encompass
  156. /// the state of a program.
  157. explicit Environment(DataflowAnalysisContext &DACtx);
  158. Environment(const Environment &Other);
  159. Environment &operator=(const Environment &Other);
  160. Environment(Environment &&Other) = default;
  161. Environment &operator=(Environment &&Other) = default;
  162. /// Creates an environment that uses `DACtx` to store objects that encompass
  163. /// the state of a program.
  164. ///
  165. /// If `DeclCtx` is a function, initializes the environment with symbolic
  166. /// representations of the function parameters.
  167. ///
  168. /// If `DeclCtx` is a non-static member function, initializes the environment
  169. /// with a symbolic representation of the `this` pointee.
  170. Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
  171. const DataflowAnalysisContext::Options &getAnalysisOptions() {
  172. return DACtx->getOptions();
  173. }
  174. /// Creates and returns an environment to use for an inline analysis of the
  175. /// callee. Uses the storage location from each argument in the `Call` as the
  176. /// storage location for the corresponding parameter in the callee.
  177. ///
  178. /// Requirements:
  179. ///
  180. /// The callee of `Call` must be a `FunctionDecl`.
  181. ///
  182. /// The body of the callee must not reference globals.
  183. ///
  184. /// The arguments of `Call` must map 1:1 to the callee's parameters.
  185. Environment pushCall(const CallExpr *Call) const;
  186. Environment pushCall(const CXXConstructExpr *Call) const;
  187. /// Moves gathered information back into `this` from a `CalleeEnv` created via
  188. /// `pushCall`.
  189. void popCall(const Environment &CalleeEnv);
  190. /// Returns true if and only if the environment is equivalent to `Other`, i.e
  191. /// the two environments:
  192. /// - have the same mappings from declarations to storage locations,
  193. /// - have the same mappings from expressions to storage locations,
  194. /// - have the same or equivalent (according to `Model`) values assigned to
  195. /// the same storage locations.
  196. ///
  197. /// Requirements:
  198. ///
  199. /// `Other` and `this` must use the same `DataflowAnalysisContext`.
  200. bool equivalentTo(const Environment &Other,
  201. Environment::ValueModel &Model) const;
  202. /// Joins the environment with `Other` by taking the intersection of storage
  203. /// locations and values that are stored in them. Distinct values that are
  204. /// assigned to the same storage locations in the environment and `Other` are
  205. /// merged using `Model`.
  206. ///
  207. /// Requirements:
  208. ///
  209. /// `Other` and `this` must use the same `DataflowAnalysisContext`.
  210. LatticeJoinEffect join(const Environment &Other,
  211. Environment::ValueModel &Model);
  212. /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
  213. /// approximation.
  214. ///
  215. /// Requirements:
  216. ///
  217. /// `PrevEnv` must be the immediate previous version of the environment.
  218. /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
  219. LatticeJoinEffect widen(const Environment &PrevEnv,
  220. Environment::ValueModel &Model);
  221. // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
  222. // `getStableStorageLocation`, or something more appropriate.
  223. /// Creates a storage location appropriate for `Type`. Does not assign a value
  224. /// to the returned storage location in the environment.
  225. ///
  226. /// Requirements:
  227. ///
  228. /// `Type` must not be null.
  229. StorageLocation &createStorageLocation(QualType Type);
  230. /// Creates a storage location for `D`. Does not assign the returned storage
  231. /// location to `D` in the environment. Does not assign a value to the
  232. /// returned storage location in the environment.
  233. StorageLocation &createStorageLocation(const VarDecl &D);
  234. /// Creates a storage location for `E`. Does not assign the returned storage
  235. /// location to `E` in the environment. Does not assign a value to the
  236. /// returned storage location in the environment.
  237. StorageLocation &createStorageLocation(const Expr &E);
  238. /// Assigns `Loc` as the storage location of `D` in the environment.
  239. ///
  240. /// Requirements:
  241. ///
  242. /// `D` must not be assigned a storage location in the environment.
  243. void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
  244. /// Returns the storage location assigned to `D` in the environment, applying
  245. /// the `SP` policy for skipping past indirections, or null if `D` isn't
  246. /// assigned a storage location in the environment.
  247. StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const;
  248. /// Assigns `Loc` as the storage location of `E` in the environment.
  249. ///
  250. /// Requirements:
  251. ///
  252. /// `E` must not be assigned a storage location in the environment.
  253. void setStorageLocation(const Expr &E, StorageLocation &Loc);
  254. /// Returns the storage location assigned to `E` in the environment, applying
  255. /// the `SP` policy for skipping past indirections, or null if `E` isn't
  256. /// assigned a storage location in the environment.
  257. StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const;
  258. /// Returns the storage location assigned to the `this` pointee in the
  259. /// environment or null if the `this` pointee has no assigned storage location
  260. /// in the environment.
  261. StorageLocation *getThisPointeeStorageLocation() const;
  262. /// Returns the storage location of the return value or null, if unset.
  263. StorageLocation *getReturnStorageLocation() const;
  264. /// Returns a pointer value that represents a null pointer. Calls with
  265. /// `PointeeType` that are canonically equivalent will return the same result.
  266. PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
  267. /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
  268. /// return null. If `Type` is a pointer or reference type, creates all the
  269. /// necessary storage locations and values for indirections until it finds a
  270. /// non-pointer/non-reference type.
  271. ///
  272. /// Requirements:
  273. ///
  274. /// `Type` must not be null.
  275. Value *createValue(QualType Type);
  276. /// Assigns `Val` as the value of `Loc` in the environment.
  277. void setValue(const StorageLocation &Loc, Value &Val);
  278. /// Returns the value assigned to `Loc` in the environment or null if `Loc`
  279. /// isn't assigned a value in the environment.
  280. Value *getValue(const StorageLocation &Loc) const;
  281. /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D`
  282. /// is assigned a storage location in the environment, otherwise returns null.
  283. Value *getValue(const ValueDecl &D, SkipPast SP) const;
  284. /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E`
  285. /// is assigned a storage location in the environment, otherwise returns null.
  286. Value *getValue(const Expr &E, SkipPast SP) const;
  287. /// Transfers ownership of `Loc` to the analysis context and returns a
  288. /// reference to it.
  289. ///
  290. /// Requirements:
  291. ///
  292. /// `Loc` must not be null.
  293. template <typename T>
  294. std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
  295. takeOwnership(std::unique_ptr<T> Loc) {
  296. return DACtx->takeOwnership(std::move(Loc));
  297. }
  298. /// Transfers ownership of `Val` to the analysis context and returns a
  299. /// reference to it.
  300. ///
  301. /// Requirements:
  302. ///
  303. /// `Val` must not be null.
  304. template <typename T>
  305. std::enable_if_t<std::is_base_of<Value, T>::value, T &>
  306. takeOwnership(std::unique_ptr<T> Val) {
  307. return DACtx->takeOwnership(std::move(Val));
  308. }
  309. /// Returns a symbolic boolean value that models a boolean literal equal to
  310. /// `Value`
  311. AtomicBoolValue &getBoolLiteralValue(bool Value) const {
  312. return DACtx->getBoolLiteralValue(Value);
  313. }
  314. /// Returns an atomic boolean value.
  315. BoolValue &makeAtomicBoolValue() const {
  316. return DACtx->createAtomicBoolValue();
  317. }
  318. /// Returns a unique instance of boolean Top.
  319. BoolValue &makeTopBoolValue() const {
  320. return DACtx->createTopBoolValue();
  321. }
  322. /// Returns a boolean value that represents the conjunction of `LHS` and
  323. /// `RHS`. Subsequent calls with the same arguments, regardless of their
  324. /// order, will return the same result. If the given boolean values represent
  325. /// the same value, the result will be the value itself.
  326. BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
  327. return DACtx->getOrCreateConjunction(LHS, RHS);
  328. }
  329. /// Returns a boolean value that represents the disjunction of `LHS` and
  330. /// `RHS`. Subsequent calls with the same arguments, regardless of their
  331. /// order, will return the same result. If the given boolean values represent
  332. /// the same value, the result will be the value itself.
  333. BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
  334. return DACtx->getOrCreateDisjunction(LHS, RHS);
  335. }
  336. /// Returns a boolean value that represents the negation of `Val`. Subsequent
  337. /// calls with the same argument will return the same result.
  338. BoolValue &makeNot(BoolValue &Val) const {
  339. return DACtx->getOrCreateNegation(Val);
  340. }
  341. /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
  342. /// the same arguments, will return the same result. If the given boolean
  343. /// values represent the same value, the result will be a value that
  344. /// represents the true boolean literal.
  345. BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
  346. return DACtx->getOrCreateImplication(LHS, RHS);
  347. }
  348. /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
  349. /// the same arguments, regardless of their order, will return the same
  350. /// result. If the given boolean values represent the same value, the result
  351. /// will be a value that represents the true boolean literal.
  352. BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
  353. return DACtx->getOrCreateIff(LHS, RHS);
  354. }
  355. /// Returns the token that identifies the flow condition of the environment.
  356. AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; }
  357. /// Builds and returns the logical formula defining the flow condition
  358. /// identified by `Token`. If a value in the formula is present as a key in
  359. /// `Substitutions`, it will be substituted with the value it maps to.
  360. BoolValue &buildAndSubstituteFlowCondition(
  361. AtomicBoolValue &Token,
  362. llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) {
  363. return DACtx->buildAndSubstituteFlowCondition(Token,
  364. std::move(Substitutions));
  365. }
  366. /// Adds `Val` to the set of clauses that constitute the flow condition.
  367. void addToFlowCondition(BoolValue &Val);
  368. /// Returns true if and only if the clauses that constitute the flow condition
  369. /// imply that `Val` is true.
  370. bool flowConditionImplies(BoolValue &Val) const;
  371. /// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
  372. /// returns null.
  373. const DeclContext *getDeclCtx() const { return CallStack.back(); }
  374. /// Returns whether this `Environment` can be extended to analyze the given
  375. /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
  376. /// given `MaxDepth`.
  377. bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
  378. /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
  379. /// returns null.
  380. const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) {
  381. return DACtx->getControlFlowContext(F);
  382. }
  383. LLVM_DUMP_METHOD void dump() const;
  384. LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
  385. private:
  386. /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
  387. /// return null.
  388. ///
  389. /// Recursively initializes storage locations and values until it sees a
  390. /// self-referential pointer or reference type. `Visited` is used to track
  391. /// which types appeared in the reference/pointer chain in order to avoid
  392. /// creating a cyclic dependency with self-referential pointers/references.
  393. ///
  394. /// Requirements:
  395. ///
  396. /// `Type` must not be null.
  397. Value *createValueUnlessSelfReferential(QualType Type,
  398. llvm::DenseSet<QualType> &Visited,
  399. int Depth, int &CreatedValuesCount);
  400. StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
  401. const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;
  402. /// Shared implementation of `pushCall` overloads. Note that unlike
  403. /// `pushCall`, this member is invoked on the environment of the callee, not
  404. /// of the caller.
  405. void pushCallInternal(const FunctionDecl *FuncDecl,
  406. ArrayRef<const Expr *> Args);
  407. /// Assigns storage locations and values to all variables in `Vars`.
  408. void initVars(llvm::DenseSet<const VarDecl *> Vars);
  409. // `DACtx` is not null and not owned by this object.
  410. DataflowAnalysisContext *DACtx;
  411. // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a
  412. // separate call-context object, shared between environments in the same call.
  413. // https://github.com/llvm/llvm-project/issues/59005
  414. // `DeclContext` of the block being analysed if provided.
  415. std::vector<const DeclContext *> CallStack;
  416. // In a properly initialized `Environment`, `ReturnLoc` should only be null if
  417. // its `DeclContext` could not be cast to a `FunctionDecl`.
  418. StorageLocation *ReturnLoc = nullptr;
  419. // The storage location of the `this` pointee. Should only be null if the
  420. // function being analyzed is only a function and not a method.
  421. StorageLocation *ThisPointeeLoc = nullptr;
  422. // Maps from program declarations and statements to storage locations that are
  423. // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
  424. // include only storage locations that are in scope for a particular basic
  425. // block.
  426. llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
  427. llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
  428. llvm::DenseMap<const StorageLocation *, Value *> LocToVal;
  429. // Maps locations of struct members to symbolic values of the structs that own
  430. // them and the decls of the struct members.
  431. llvm::DenseMap<const StorageLocation *,
  432. std::pair<StructValue *, const ValueDecl *>>
  433. MemberLocToStruct;
  434. AtomicBoolValue *FlowConditionToken;
  435. };
  436. } // namespace dataflow
  437. } // namespace clang
  438. #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
  439. #ifdef __GNUC__
  440. #pragma GCC diagnostic pop
  441. #endif