ExplodedGraph.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. //=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines the template classes ExplodedNode and ExplodedGraph,
  11. // which represent a path-sensitive, intra-procedural "exploded graph."
  12. // See "Precise interprocedural dataflow analysis via graph reachability"
  13. // by Reps, Horwitz, and Sagiv
  14. // (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
  15. // exploded graph.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
  19. #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
  20. #include "clang/AST/Decl.h"
  21. #include "clang/Analysis/AnalysisContext.h"
  22. #include "clang/Analysis/ProgramPoint.h"
  23. #include "clang/Analysis/Support/BumpVector.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  25. #include "llvm/ADT/DepthFirstIterator.h"
  26. #include "llvm/ADT/FoldingSet.h"
  27. #include "llvm/ADT/GraphTraits.h"
  28. #include "llvm/ADT/SmallPtrSet.h"
  29. #include "llvm/ADT/SmallVector.h"
  30. #include "llvm/Support/Allocator.h"
  31. #include "llvm/Support/Casting.h"
  32. #include <memory>
  33. #include <vector>
  34. namespace clang {
  35. class CFG;
  36. namespace ento {
  37. class ExplodedGraph;
  38. //===----------------------------------------------------------------------===//
  39. // ExplodedGraph "implementation" classes. These classes are not typed to
  40. // contain a specific kind of state. Typed-specialized versions are defined
  41. // on top of these classes.
  42. //===----------------------------------------------------------------------===//
  43. // ExplodedNode is not constified all over the engine because we need to add
  44. // successors to it at any time after creating it.
  45. class ExplodedNode : public llvm::FoldingSetNode {
  46. friend class ExplodedGraph;
  47. friend class CoreEngine;
  48. friend class NodeBuilder;
  49. friend class BranchNodeBuilder;
  50. friend class IndirectGotoNodeBuilder;
  51. friend class SwitchNodeBuilder;
  52. friend class EndOfFunctionNodeBuilder;
  53. /// Efficiently stores a list of ExplodedNodes, or an optional flag.
  54. ///
  55. /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing
  56. /// for the case when there is only one node in the group. This is a fairly
  57. /// common case in an ExplodedGraph, where most nodes have only one
  58. /// predecessor and many have only one successor. It can also be used to
  59. /// store a flag rather than a node list, which ExplodedNode uses to mark
  60. /// whether a node is a sink. If the flag is set, the group is implicitly
  61. /// empty and no nodes may be added.
  62. class NodeGroup {
  63. // Conceptually a discriminated union. If the low bit is set, the node is
  64. // a sink. If the low bit is not set, the pointer refers to the storage
  65. // for the nodes in the group.
  66. // This is not a PointerIntPair in order to keep the storage type opaque.
  67. uintptr_t P;
  68. public:
  69. NodeGroup(bool Flag = false) : P(Flag) {
  70. assert(getFlag() == Flag);
  71. }
  72. ExplodedNode * const *begin() const;
  73. ExplodedNode * const *end() const;
  74. unsigned size() const;
  75. bool empty() const { return P == 0 || getFlag() != 0; }
  76. /// Adds a node to the list.
  77. ///
  78. /// The group must not have been created with its flag set.
  79. void addNode(ExplodedNode *N, ExplodedGraph &G);
  80. /// Replaces the single node in this group with a new node.
  81. ///
  82. /// Note that this should only be used when you know the group was not
  83. /// created with its flag set, and that the group is empty or contains
  84. /// only a single node.
  85. void replaceNode(ExplodedNode *node);
  86. /// Returns whether this group was created with its flag set.
  87. bool getFlag() const {
  88. return (P & 1);
  89. }
  90. };
  91. /// Location - The program location (within a function body) associated
  92. /// with this node.
  93. const ProgramPoint Location;
  94. /// State - The state associated with this node.
  95. ProgramStateRef State;
  96. /// Preds - The predecessors of this node.
  97. NodeGroup Preds;
  98. /// Succs - The successors of this node.
  99. NodeGroup Succs;
  100. public:
  101. explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
  102. bool IsSink)
  103. : Location(loc), State(state), Succs(IsSink) {
  104. assert(isSink() == IsSink);
  105. }
  106. /// getLocation - Returns the edge associated with the given node.
  107. ProgramPoint getLocation() const { return Location; }
  108. const LocationContext *getLocationContext() const {
  109. return getLocation().getLocationContext();
  110. }
  111. const StackFrameContext *getStackFrame() const {
  112. return getLocationContext()->getCurrentStackFrame();
  113. }
  114. const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
  115. CFG &getCFG() const { return *getLocationContext()->getCFG(); }
  116. ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
  117. template <typename T>
  118. T &getAnalysis() const {
  119. return *getLocationContext()->getAnalysis<T>();
  120. }
  121. const ProgramStateRef &getState() const { return State; }
  122. template <typename T>
  123. Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION {
  124. return Location.getAs<T>();
  125. }
  126. static void Profile(llvm::FoldingSetNodeID &ID,
  127. const ProgramPoint &Loc,
  128. const ProgramStateRef &state,
  129. bool IsSink) {
  130. ID.Add(Loc);
  131. ID.AddPointer(state.get());
  132. ID.AddBoolean(IsSink);
  133. }
  134. void Profile(llvm::FoldingSetNodeID& ID) const {
  135. // We avoid copy constructors by not using accessors.
  136. Profile(ID, Location, State, isSink());
  137. }
  138. /// addPredeccessor - Adds a predecessor to the current node, and
  139. /// in tandem add this node as a successor of the other node.
  140. void addPredecessor(ExplodedNode *V, ExplodedGraph &G);
  141. unsigned succ_size() const { return Succs.size(); }
  142. unsigned pred_size() const { return Preds.size(); }
  143. bool succ_empty() const { return Succs.empty(); }
  144. bool pred_empty() const { return Preds.empty(); }
  145. bool isSink() const { return Succs.getFlag(); }
  146. bool hasSinglePred() const {
  147. return (pred_size() == 1);
  148. }
  149. ExplodedNode *getFirstPred() {
  150. return pred_empty() ? nullptr : *(pred_begin());
  151. }
  152. const ExplodedNode *getFirstPred() const {
  153. return const_cast<ExplodedNode*>(this)->getFirstPred();
  154. }
  155. const ExplodedNode *getFirstSucc() const {
  156. return succ_empty() ? nullptr : *(succ_begin());
  157. }
  158. // Iterators over successor and predecessor vertices.
  159. typedef ExplodedNode* const * succ_iterator;
  160. typedef const ExplodedNode* const * const_succ_iterator;
  161. typedef ExplodedNode* const * pred_iterator;
  162. typedef const ExplodedNode* const * const_pred_iterator;
  163. pred_iterator pred_begin() { return Preds.begin(); }
  164. pred_iterator pred_end() { return Preds.end(); }
  165. const_pred_iterator pred_begin() const {
  166. return const_cast<ExplodedNode*>(this)->pred_begin();
  167. }
  168. const_pred_iterator pred_end() const {
  169. return const_cast<ExplodedNode*>(this)->pred_end();
  170. }
  171. succ_iterator succ_begin() { return Succs.begin(); }
  172. succ_iterator succ_end() { return Succs.end(); }
  173. const_succ_iterator succ_begin() const {
  174. return const_cast<ExplodedNode*>(this)->succ_begin();
  175. }
  176. const_succ_iterator succ_end() const {
  177. return const_cast<ExplodedNode*>(this)->succ_end();
  178. }
  179. // For debugging.
  180. public:
  181. class Auditor {
  182. public:
  183. virtual ~Auditor();
  184. virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0;
  185. };
  186. static void SetAuditor(Auditor* A);
  187. private:
  188. void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
  189. void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
  190. };
  191. typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>
  192. InterExplodedGraphMap;
  193. class ExplodedGraph {
  194. protected:
  195. friend class CoreEngine;
  196. // Type definitions.
  197. typedef std::vector<ExplodedNode *> NodeVector;
  198. /// The roots of the simulation graph. Usually there will be only
  199. /// one, but clients are free to establish multiple subgraphs within a single
  200. /// SimulGraph. Moreover, these subgraphs can often merge when paths from
  201. /// different roots reach the same state at the same program location.
  202. NodeVector Roots;
  203. /// The nodes in the simulation graph which have been
  204. /// specially marked as the endpoint of an abstract simulation path.
  205. NodeVector EndNodes;
  206. /// Nodes - The nodes in the graph.
  207. llvm::FoldingSet<ExplodedNode> Nodes;
  208. /// BVC - Allocator and context for allocating nodes and their predecessor
  209. /// and successor groups.
  210. BumpVectorContext BVC;
  211. /// NumNodes - The number of nodes in the graph.
  212. unsigned NumNodes;
  213. /// A list of recently allocated nodes that can potentially be recycled.
  214. NodeVector ChangedNodes;
  215. /// A list of nodes that can be reused.
  216. NodeVector FreeNodes;
  217. /// Determines how often nodes are reclaimed.
  218. ///
  219. /// If this is 0, nodes will never be reclaimed.
  220. unsigned ReclaimNodeInterval;
  221. /// Counter to determine when to reclaim nodes.
  222. unsigned ReclaimCounter;
  223. public:
  224. /// \brief Retrieve the node associated with a (Location,State) pair,
  225. /// where the 'Location' is a ProgramPoint in the CFG. If no node for
  226. /// this pair exists, it is created. IsNew is set to true if
  227. /// the node was freshly created.
  228. ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State,
  229. bool IsSink = false,
  230. bool* IsNew = nullptr);
  231. std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
  232. return llvm::make_unique<ExplodedGraph>();
  233. }
  234. /// addRoot - Add an untyped node to the set of roots.
  235. ExplodedNode *addRoot(ExplodedNode *V) {
  236. Roots.push_back(V);
  237. return V;
  238. }
  239. /// addEndOfPath - Add an untyped node to the set of EOP nodes.
  240. ExplodedNode *addEndOfPath(ExplodedNode *V) {
  241. EndNodes.push_back(V);
  242. return V;
  243. }
  244. ExplodedGraph();
  245. ~ExplodedGraph();
  246. unsigned num_roots() const { return Roots.size(); }
  247. unsigned num_eops() const { return EndNodes.size(); }
  248. bool empty() const { return NumNodes == 0; }
  249. unsigned size() const { return NumNodes; }
  250. // Iterators.
  251. typedef ExplodedNode NodeTy;
  252. typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
  253. typedef NodeVector::iterator roots_iterator;
  254. typedef NodeVector::const_iterator const_roots_iterator;
  255. typedef NodeVector::iterator eop_iterator;
  256. typedef NodeVector::const_iterator const_eop_iterator;
  257. typedef AllNodesTy::iterator node_iterator;
  258. typedef AllNodesTy::const_iterator const_node_iterator;
  259. node_iterator nodes_begin() { return Nodes.begin(); }
  260. node_iterator nodes_end() { return Nodes.end(); }
  261. const_node_iterator nodes_begin() const { return Nodes.begin(); }
  262. const_node_iterator nodes_end() const { return Nodes.end(); }
  263. roots_iterator roots_begin() { return Roots.begin(); }
  264. roots_iterator roots_end() { return Roots.end(); }
  265. const_roots_iterator roots_begin() const { return Roots.begin(); }
  266. const_roots_iterator roots_end() const { return Roots.end(); }
  267. eop_iterator eop_begin() { return EndNodes.begin(); }
  268. eop_iterator eop_end() { return EndNodes.end(); }
  269. const_eop_iterator eop_begin() const { return EndNodes.begin(); }
  270. const_eop_iterator eop_end() const { return EndNodes.end(); }
  271. llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
  272. BumpVectorContext &getNodeAllocator() { return BVC; }
  273. typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
  274. /// Creates a trimmed version of the graph that only contains paths leading
  275. /// to the given nodes.
  276. ///
  277. /// \param Nodes The nodes which must appear in the final graph. Presumably
  278. /// these are end-of-path nodes (i.e. they have no successors).
  279. /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in
  280. /// the returned graph.
  281. /// \param[out] InverseMap An optional map from nodes in the returned graph to
  282. /// nodes in this graph.
  283. /// \returns The trimmed graph
  284. std::unique_ptr<ExplodedGraph>
  285. trim(ArrayRef<const NodeTy *> Nodes,
  286. InterExplodedGraphMap *ForwardMap = nullptr,
  287. InterExplodedGraphMap *InverseMap = nullptr) const;
  288. /// Enable tracking of recently allocated nodes for potential reclamation
  289. /// when calling reclaimRecentlyAllocatedNodes().
  290. void enableNodeReclamation(unsigned Interval) {
  291. ReclaimCounter = ReclaimNodeInterval = Interval;
  292. }
  293. /// Reclaim "uninteresting" nodes created since the last time this method
  294. /// was called.
  295. void reclaimRecentlyAllocatedNodes();
  296. /// \brief Returns true if nodes for the given expression kind are always
  297. /// kept around.
  298. static bool isInterestingLValueExpr(const Expr *Ex);
  299. private:
  300. bool shouldCollect(const ExplodedNode *node);
  301. void collectNode(ExplodedNode *node);
  302. };
  303. class ExplodedNodeSet {
  304. typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
  305. ImplTy Impl;
  306. public:
  307. ExplodedNodeSet(ExplodedNode *N) {
  308. assert (N && !static_cast<ExplodedNode*>(N)->isSink());
  309. Impl.insert(N);
  310. }
  311. ExplodedNodeSet() {}
  312. inline void Add(ExplodedNode *N) {
  313. if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
  314. }
  315. typedef ImplTy::iterator iterator;
  316. typedef ImplTy::const_iterator const_iterator;
  317. unsigned size() const { return Impl.size(); }
  318. bool empty() const { return Impl.empty(); }
  319. bool erase(ExplodedNode *N) { return Impl.erase(N); }
  320. void clear() { Impl.clear(); }
  321. void insert(const ExplodedNodeSet &S) {
  322. assert(&S != this);
  323. if (empty())
  324. Impl = S.Impl;
  325. else
  326. Impl.insert(S.begin(), S.end());
  327. }
  328. inline iterator begin() { return Impl.begin(); }
  329. inline iterator end() { return Impl.end(); }
  330. inline const_iterator begin() const { return Impl.begin(); }
  331. inline const_iterator end() const { return Impl.end(); }
  332. };
  333. } // end GR namespace
  334. } // end clang namespace
  335. // GraphTraits
  336. namespace llvm {
  337. template<> struct GraphTraits<clang::ento::ExplodedNode*> {
  338. typedef clang::ento::ExplodedNode NodeType;
  339. typedef NodeType::succ_iterator ChildIteratorType;
  340. typedef llvm::df_iterator<NodeType*> nodes_iterator;
  341. static inline NodeType* getEntryNode(NodeType* N) {
  342. return N;
  343. }
  344. static inline ChildIteratorType child_begin(NodeType* N) {
  345. return N->succ_begin();
  346. }
  347. static inline ChildIteratorType child_end(NodeType* N) {
  348. return N->succ_end();
  349. }
  350. static inline nodes_iterator nodes_begin(NodeType* N) {
  351. return df_begin(N);
  352. }
  353. static inline nodes_iterator nodes_end(NodeType* N) {
  354. return df_end(N);
  355. }
  356. };
  357. template<> struct GraphTraits<const clang::ento::ExplodedNode*> {
  358. typedef const clang::ento::ExplodedNode NodeType;
  359. typedef NodeType::const_succ_iterator ChildIteratorType;
  360. typedef llvm::df_iterator<NodeType*> nodes_iterator;
  361. static inline NodeType* getEntryNode(NodeType* N) {
  362. return N;
  363. }
  364. static inline ChildIteratorType child_begin(NodeType* N) {
  365. return N->succ_begin();
  366. }
  367. static inline ChildIteratorType child_end(NodeType* N) {
  368. return N->succ_end();
  369. }
  370. static inline nodes_iterator nodes_begin(NodeType* N) {
  371. return df_begin(N);
  372. }
  373. static inline nodes_iterator nodes_end(NodeType* N) {
  374. return df_end(N);
  375. }
  376. };
  377. } // end llvm namespace
  378. #endif