CoreEngine.h revision f24af5bc2e01ca8e7396ed997378a77fddfa521e
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//==- GREngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//                     The LLVM Compiler Infrastructure
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// License. See LICENSE.TXT for details.
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//===----------------------------------------------------------------------===//
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  This file defines a generic engine for intraprocedural, path-sensitive,
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  dataflow analysis via graph reachability engine.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//===----------------------------------------------------------------------===//
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define LLVM_CLANG_ANALYSIS_GRENGINE
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "clang/Analysis/PathSensitive/GRWorkList.h"
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "llvm/ADT/OwningPtr.h"
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace clang {
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class CFG;
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class GRNodeBuilderImpl;
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class GRWorkList;
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class GREngineImpl {
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)protected:
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  friend class GRNodeBuilderImpl;
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
32f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu  typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3476c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)  /// cfg - The control-flow graph of the function being analyzed.
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CFG& cfg;
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  /// G - The simulation graph.  Each node is a (location,state) pair.
385267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  llvm::OwningPtr<ExplodedGraphImpl> G;
395267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
40f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu  /// ParentMap - A lazily populated map from a Stmt* to its parent Stmt*.
41f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu  void* ParentMap;
42591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  /// CurrentBlkExpr - The current Block-level expression being processed.
4451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  ///  This is used when lazily populating ParentMap.
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  Stmt* CurrentBlkExpr;
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  /// WList - A set of queued nodes that need to be processed by the
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  worklist algorithm.  It is up to the implementation of WList to decide
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  the order that nodes are processed.
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  GRWorkList* WList;
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  void GenerateNode(const ProgramPoint& Loc, void* State,
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    ExplodedNodeImpl* Pred = NULL);
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  /// getInitialState - Gets the void* representing the initial 'state'
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  of the analysis.  This is simply a wrapper (implemented
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  in GREngine) that performs type erasure on the initial
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  state returned by the checker object.
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void* getInitialState() = 0;
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  void HandleBlockExit(const BlockExit& E, ExplodedNodeImpl* Pred);
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  void HandlePostStmt(const PostStmt& S, CFGBlock* B,
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      unsigned StmtIdx, ExplodedNodeImpl *Pred);
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void* ProcessEOP(CFGBlock* Blk, void* State) = 0;
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void ProcessStmt(Stmt* S, GRNodeBuilderImpl& Builder) = 0;
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void ProcessTerminator(Stmt* Terminator, CFGBlock* B,
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                 ExplodedNodeImpl* Pred) = 0;
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)private:
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  GREngineImpl(const GREngineImpl&); // Do not implement.
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  GREngineImpl& operator=(const GREngineImpl&);
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)protected:
79d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)  GREngineImpl(CFG& c, ExplodedGraphImpl* g, GRWorkList* wl)
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   : cfg(c), G(g), WList(wl) {}
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public:
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ///  steps.  Returns true if there is still simulation state on the worklist.
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  bool ExecuteWorkList(unsigned Steps = 1000000);
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
87323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  virtual ~GREngineImpl() {}
881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)};
89323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
90323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)class GRNodeBuilderImpl {
911e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)  GREngineImpl& Eng;
921e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)  CFGBlock& B;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  const unsigned Idx;
941e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)  ExplodedNodeImpl* LastNode;
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  bool HasGeneratedNode;
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  bool Populated;
9710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
98591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch  typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
9910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch  DeferredTy Deferred;
100591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
101591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch  void GenerateAutoTransition(ExplodedNodeImpl* N);
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public:
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  GRNodeBuilderImpl(CFGBlock* b, unsigned idx,
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    ExplodedNodeImpl* N, GREngineImpl* e);
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
107323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  ~GRNodeBuilderImpl();
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  inline ExplodedNodeImpl* getLastNode() {
112323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    return LastNode ? (LastNode->isInfeasible() ? NULL : LastNode) : NULL;
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                     ExplodedNodeImpl* Pred);
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
118323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State) {
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ExplodedNodeImpl* N = getLastNode();
120591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    assert (N && "Predecessor of new node is infeasible.");
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return generateNodeImpl(S, State, N);
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
12351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
124  Stmt* getStmt() const { return B[Idx]; }
125
126  CFGBlock* getBlock() const { return &B; }
127};
128
129template<typename CHECKER>
130class GRNodeBuilder  {
131  typedef CHECKER                                CheckerTy;
132  typedef typename CheckerTy::StateTy            StateTy;
133  typedef ExplodedGraph<CheckerTy>               GraphTy;
134  typedef typename GraphTy::NodeTy               NodeTy;
135
136  GRNodeBuilderImpl& NB;
137
138public:
139  const GraphTy& getGraph() const {
140    return static_cast<const GraphTy&>(NB.getGraph());
141  }
142
143  NodeTy* getLastNode() const {
144    return static_cast<NodeTy*>(NB.getLastNode());
145  }
146
147  NodeTy* generateNode(Stmt* S, StateTy State, NodeTy* Pred) {
148    void *state = GRTrait<StateTy>::toPtr(State);
149    return static_cast<NodeTy*>(NB.generateNodeImpl(S, state, Pred));
150  }
151
152  NodeTy* generateNode(Stmt* S, StateTy State) {
153    void *state = GRTrait<StateTy>::toPtr(State);
154    return static_cast<NodeTy*>(NB.generateNodeImpl(S, state));
155  }
156};
157
158
159template<typename CHECKER>
160class GREngine : public GREngineImpl {
161public:
162  typedef CHECKER                                CheckerTy;
163  typedef typename CheckerTy::StateTy            StateTy;
164  typedef ExplodedGraph<CheckerTy>               GraphTy;
165  typedef typename GraphTy::NodeTy               NodeTy;
166
167protected:
168  // A local reference to the checker that avoids an indirect access
169  // via the Graph.
170  CheckerTy* Checker;
171
172
173  virtual void* getInitialState() {
174    return GRTrait<StateTy>::toPtr(getCheckerState()->getInitialState());
175  }
176
177  virtual void* ProcessEOP(CFGBlock* Blk, void* State) {
178    // FIXME: Perform dispatch to adjust state.
179    return State;
180  }
181
182  virtual void ProcessStmt(Stmt* S, GRNodeBuilderImpl& BuilderImpl) {
183    GRNodeBuilder<CHECKER> Builder(BuilderImpl);
184    Checker->ProcessStmt(S, Builder);
185  }
186
187  virtual void ProcessTerminator(Stmt* Terminator, CFGBlock* B,
188                                 ExplodedNodeImpl* Pred) {
189    // FIXME: Dispatch.
190  }
191
192
193public:
194  /// Construct a GREngine object to analyze the provided CFG using
195  ///  a DFS exploration of the exploded graph.
196  GREngine(CFG& Cfg)
197  : GREngineImpl(cfg, new GraphTy(), GRWorkList::MakeDFS()),
198      Checker(static_cast<GraphTy*>(G.get())->getCheckerState()) {}
199
200  /// Construct a GREngine object to analyze the provided CFG and to
201  ///  use the provided worklist object to execute the worklist algorithm.
202  ///  The GREngine object assumes ownership of 'wlist'.
203  GREngine(CFG& cfg, GRWorkList* wlist)
204    : GREngineImpl(cfg, new GraphTy(), wlist),
205      Checker(static_cast<GraphTy*>(G.get())->getCheckerState()) {}
206
207  virtual ~GREngine() {}
208
209  /// getGraph - Returns the exploded graph.
210  GraphTy& getGraph() {
211    return *static_cast<GraphTy*>(G.get());
212  }
213
214  /// getCheckerState - Returns the internal checker state.
215  CheckerTy& getCheckerState() {
216    return *Checker;
217  }
218
219  /// takeGraph - Returns the exploded graph.  Ownership of the graph is
220  ///  transfered to the caller.
221  GraphTy* takeGraph() {
222    return static_cast<GraphTy*>(G.take());
223  }
224};
225
226} // end clang namespace
227
228#endif
229