CoreEngine.h revision 5903a373db3d27794c90b25687e0dd6adb0e497d
1//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- 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 a generic engine for intraprocedural, path-sensitive, 11// dataflow analysis via graph reachability. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_GR_COREENGINE 16#define LLVM_CLANG_GR_COREENGINE 17 18#include "clang/AST/Expr.h" 19#include "clang/Analysis/AnalysisContext.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" 23#include "llvm/ADT/OwningPtr.h" 24 25namespace clang { 26 27class ProgramPointTag; 28 29namespace ento { 30 31class NodeBuilder; 32 33//===----------------------------------------------------------------------===// 34/// CoreEngine - Implements the core logic of the graph-reachability 35/// analysis. It traverses the CFG and generates the ExplodedGraph. 36/// Program "states" are treated as opaque void pointers. 37/// The template class CoreEngine (which subclasses CoreEngine) 38/// provides the matching component to the engine that knows the actual types 39/// for states. Note that this engine only dispatches to transfer functions 40/// at the statement and block-level. The analyses themselves must implement 41/// any transfer function logic and the sub-expression level (if any). 42class CoreEngine { 43 friend struct NodeBuilderContext; 44 friend class NodeBuilder; 45 friend class CommonNodeBuilder; 46 friend class IndirectGotoNodeBuilder; 47 friend class SwitchNodeBuilder; 48 friend class EndOfFunctionNodeBuilder; 49public: 50 typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > 51 BlocksExhausted; 52 53 typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > 54 BlocksAborted; 55 56private: 57 58 SubEngine& SubEng; 59 60 /// G - The simulation graph. Each node is a (location,state) pair. 61 OwningPtr<ExplodedGraph> G; 62 63 /// WList - A set of queued nodes that need to be processed by the 64 /// worklist algorithm. It is up to the implementation of WList to decide 65 /// the order that nodes are processed. 66 WorkList* WList; 67 68 /// BCounterFactory - A factory object for created BlockCounter objects. 69 /// These are used to record for key nodes in the ExplodedGraph the 70 /// number of times different CFGBlocks have been visited along a path. 71 BlockCounter::Factory BCounterFactory; 72 73 /// The locations where we stopped doing work because we visited a location 74 /// too many times. 75 BlocksExhausted blocksExhausted; 76 77 /// The locations where we stopped because the engine aborted analysis, 78 /// usually because it could not reason about something. 79 BlocksAborted blocksAborted; 80 81 /// The functions which have been analyzed through inlining. This is owned by 82 /// AnalysisConsumer. It can be null. 83 SetOfDecls *AnalyzedCallees; 84 85 void generateNode(const ProgramPoint &Loc, 86 ProgramStateRef State, 87 ExplodedNode *Pred); 88 89 void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); 90 void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); 91 void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); 92 void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); 93 94 void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, 95 ExplodedNode *Pred); 96 97private: 98 CoreEngine(const CoreEngine&); // Do not implement. 99 CoreEngine& operator=(const CoreEngine&); 100 101 ExplodedNode *generateCallExitNode(ExplodedNode *N); 102 103public: 104 /// Construct a CoreEngine object to analyze the provided CFG using 105 /// a DFS exploration of the exploded graph. 106 CoreEngine(SubEngine& subengine, SetOfDecls *VisitedCallees) 107 : SubEng(subengine), G(new ExplodedGraph()), 108 WList(WorkList::makeBFS()), 109 BCounterFactory(G->getAllocator()), 110 AnalyzedCallees(VisitedCallees) {} 111 112 ~CoreEngine() { 113 delete WList; 114 } 115 116 /// getGraph - Returns the exploded graph. 117 ExplodedGraph& getGraph() { return *G.get(); } 118 119 /// takeGraph - Returns the exploded graph. Ownership of the graph is 120 /// transferred to the caller. 121 ExplodedGraph* takeGraph() { return G.take(); } 122 123 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of 124 /// steps. Returns true if there is still simulation state on the worklist. 125 bool ExecuteWorkList(const LocationContext *L, unsigned Steps, 126 ProgramStateRef InitState); 127 void ExecuteWorkListWithInitialState(const LocationContext *L, 128 unsigned Steps, 129 ProgramStateRef InitState, 130 ExplodedNodeSet &Dst); 131 132 /// Dispatch the work list item based on the given location information. 133 /// Use Pred parameter as the predecessor state. 134 void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, 135 const WorkListUnit& WU); 136 137 // Functions for external checking of whether we have unfinished work 138 bool wasBlockAborted() const { return !blocksAborted.empty(); } 139 bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } 140 bool hasWorkRemaining() const { return wasBlocksExhausted() || 141 WList->hasWork() || 142 wasBlockAborted(); } 143 144 /// Inform the CoreEngine that a basic block was aborted because 145 /// it could not be completely analyzed. 146 void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { 147 blocksAborted.push_back(std::make_pair(block, node)); 148 } 149 150 WorkList *getWorkList() const { return WList; } 151 152 BlocksExhausted::const_iterator blocks_exhausted_begin() const { 153 return blocksExhausted.begin(); 154 } 155 BlocksExhausted::const_iterator blocks_exhausted_end() const { 156 return blocksExhausted.end(); 157 } 158 BlocksAborted::const_iterator blocks_aborted_begin() const { 159 return blocksAborted.begin(); 160 } 161 BlocksAborted::const_iterator blocks_aborted_end() const { 162 return blocksAborted.end(); 163 } 164 165 /// \brief Enqueue the given set of nodes onto the work list. 166 void enqueue(ExplodedNodeSet &Set); 167 168 /// \brief Enqueue nodes that were created as a result of processing 169 /// a statement onto the work list. 170 void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx); 171 172 /// \brief enqueue the nodes corresponding to the end of function onto the 173 /// end of path / work list. 174 void enqueueEndOfFunction(ExplodedNodeSet &Set); 175 176 /// \brief Enqueue a single node created as a result of statement processing. 177 void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); 178}; 179 180// TODO: Turn into a calss. 181struct NodeBuilderContext { 182 CoreEngine &Eng; 183 const CFGBlock *Block; 184 ExplodedNode *Pred; 185 NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N) 186 : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); } 187 188 ExplodedNode *getPred() const { return Pred; } 189 190 /// \brief Return the CFGBlock associated with this builder. 191 const CFGBlock *getBlock() const { return Block; } 192 193 /// \brief Returns the number of times the current basic block has been 194 /// visited on the exploded graph path. 195 unsigned getCurrentBlockCount() const { 196 return Eng.WList->getBlockCounter().getNumVisited( 197 Pred->getLocationContext()->getCurrentStackFrame(), 198 Block->getBlockID()); 199 } 200}; 201 202/// \class NodeBuilder 203/// \brief This is the simplest builder which generates nodes in the 204/// ExplodedGraph. 205/// 206/// The main benefit of the builder is that it automatically tracks the 207/// frontier nodes (or destination set). This is the set of nodes which should 208/// be propagated to the next step / builder. They are the nodes which have been 209/// added to the builder (either as the input node set or as the newly 210/// constructed nodes) but did not have any outgoing transitions added. 211class NodeBuilder { 212 virtual void anchor(); 213protected: 214 const NodeBuilderContext &C; 215 216 /// Specifies if the builder results have been finalized. For example, if it 217 /// is set to false, autotransitions are yet to be generated. 218 bool Finalized; 219 bool HasGeneratedNodes; 220 /// \brief The frontier set - a set of nodes which need to be propagated after 221 /// the builder dies. 222 ExplodedNodeSet &Frontier; 223 224 /// Checkes if the results are ready. 225 virtual bool checkResults() { 226 if (!Finalized) 227 return false; 228 return true; 229 } 230 231 bool hasNoSinksInFrontier() { 232 for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { 233 if ((*I)->isSink()) 234 return false; 235 } 236 return true; 237 } 238 239 /// Allow subclasses to finalize results before result_begin() is executed. 240 virtual void finalizeResults() {} 241 242 ExplodedNode *generateNodeImpl(const ProgramPoint &PP, 243 ProgramStateRef State, 244 ExplodedNode *Pred, 245 bool MarkAsSink = false); 246 247public: 248 NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 249 const NodeBuilderContext &Ctx, bool F = true) 250 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 251 Frontier.Add(SrcNode); 252 } 253 254 NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 255 const NodeBuilderContext &Ctx, bool F = true) 256 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 257 Frontier.insert(SrcSet); 258 assert(hasNoSinksInFrontier()); 259 } 260 261 virtual ~NodeBuilder() {} 262 263 /// \brief Generates a node in the ExplodedGraph. 264 /// 265 /// When a node is marked as sink, the exploration from the node is stopped - 266 /// the node becomes the last node on the path. 267 ExplodedNode *generateNode(const ProgramPoint &PP, 268 ProgramStateRef State, 269 ExplodedNode *Pred, 270 bool MarkAsSink = false) { 271 return generateNodeImpl(PP, State, Pred, MarkAsSink); 272 } 273 274 const ExplodedNodeSet &getResults() { 275 finalizeResults(); 276 assert(checkResults()); 277 return Frontier; 278 } 279 280 typedef ExplodedNodeSet::iterator iterator; 281 /// \brief Iterators through the results frontier. 282 inline iterator begin() { 283 finalizeResults(); 284 assert(checkResults()); 285 return Frontier.begin(); 286 } 287 inline iterator end() { 288 finalizeResults(); 289 return Frontier.end(); 290 } 291 292 const NodeBuilderContext &getContext() { return C; } 293 bool hasGeneratedNodes() { return HasGeneratedNodes; } 294 295 void takeNodes(const ExplodedNodeSet &S) { 296 for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) 297 Frontier.erase(*I); 298 } 299 void takeNodes(ExplodedNode *N) { Frontier.erase(N); } 300 void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } 301 void addNodes(ExplodedNode *N) { Frontier.Add(N); } 302}; 303 304/// \class NodeBuilderWithSinks 305/// \brief This node builder keeps track of the generated sink nodes. 306class NodeBuilderWithSinks: public NodeBuilder { 307 virtual void anchor(); 308protected: 309 SmallVector<ExplodedNode*, 2> sinksGenerated; 310 ProgramPoint &Location; 311 312public: 313 NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, 314 const NodeBuilderContext &Ctx, ProgramPoint &L) 315 : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} 316 ExplodedNode *generateNode(ProgramStateRef State, 317 ExplodedNode *Pred, 318 const ProgramPointTag *Tag = 0, 319 bool MarkAsSink = false) { 320 ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location); 321 322 ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink); 323 if (N && N->isSink()) 324 sinksGenerated.push_back(N); 325 return N; 326 } 327 328 const SmallVectorImpl<ExplodedNode*> &getSinks() const { 329 return sinksGenerated; 330 } 331}; 332 333/// \class StmtNodeBuilder 334/// \brief This builder class is useful for generating nodes that resulted from 335/// visiting a statement. The main difference from it's parent NodeBuilder is 336/// that it creates a statement specific ProgramPoint. 337class StmtNodeBuilder: public NodeBuilder { 338 NodeBuilder *EnclosingBldr; 339public: 340 341 /// \brief Constructs a StmtNodeBuilder. If the builder is going to process 342 /// nodes currently owned by another builder(with larger scope), use 343 /// Enclosing builder to transfer ownership. 344 StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 345 const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0) 346 : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { 347 if (EnclosingBldr) 348 EnclosingBldr->takeNodes(SrcNode); 349 } 350 351 StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 352 const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0) 353 : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { 354 if (EnclosingBldr) 355 for (ExplodedNodeSet::iterator I = SrcSet.begin(), 356 E = SrcSet.end(); I != E; ++I ) 357 EnclosingBldr->takeNodes(*I); 358 } 359 360 virtual ~StmtNodeBuilder(); 361 362 ExplodedNode *generateNode(const Stmt *S, 363 ExplodedNode *Pred, 364 ProgramStateRef St, 365 bool MarkAsSink = false, 366 const ProgramPointTag *tag = 0, 367 ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ 368 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 369 Pred->getLocationContext(), tag); 370 return generateNodeImpl(L, St, Pred, MarkAsSink); 371 } 372 373 ExplodedNode *generateNode(const ProgramPoint &PP, 374 ExplodedNode *Pred, 375 ProgramStateRef State, 376 bool MarkAsSink = false) { 377 return generateNodeImpl(PP, State, Pred, MarkAsSink); 378 } 379}; 380 381/// \brief BranchNodeBuilder is responsible for constructing the nodes 382/// corresponding to the two branches of the if statement - true and false. 383class BranchNodeBuilder: public NodeBuilder { 384 virtual void anchor(); 385 const CFGBlock *DstT; 386 const CFGBlock *DstF; 387 388 bool InFeasibleTrue; 389 bool InFeasibleFalse; 390 391public: 392 BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 393 const NodeBuilderContext &C, 394 const CFGBlock *dstT, const CFGBlock *dstF) 395 : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), 396 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { 397 // The branch node builder does not generate autotransitions. 398 // If there are no successors it means that both branches are infeasible. 399 takeNodes(SrcNode); 400 } 401 402 BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 403 const NodeBuilderContext &C, 404 const CFGBlock *dstT, const CFGBlock *dstF) 405 : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), 406 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { 407 takeNodes(SrcSet); 408 } 409 410 ExplodedNode *generateNode(ProgramStateRef State, bool branch, 411 ExplodedNode *Pred); 412 413 const CFGBlock *getTargetBlock(bool branch) const { 414 return branch ? DstT : DstF; 415 } 416 417 void markInfeasible(bool branch) { 418 if (branch) 419 InFeasibleTrue = true; 420 else 421 InFeasibleFalse = true; 422 } 423 424 bool isFeasible(bool branch) { 425 return branch ? !InFeasibleTrue : !InFeasibleFalse; 426 } 427}; 428 429class IndirectGotoNodeBuilder { 430 CoreEngine& Eng; 431 const CFGBlock *Src; 432 const CFGBlock &DispatchBlock; 433 const Expr *E; 434 ExplodedNode *Pred; 435 436public: 437 IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 438 const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) 439 : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} 440 441 class iterator { 442 CFGBlock::const_succ_iterator I; 443 444 friend class IndirectGotoNodeBuilder; 445 iterator(CFGBlock::const_succ_iterator i) : I(i) {} 446 public: 447 448 iterator &operator++() { ++I; return *this; } 449 bool operator!=(const iterator &X) const { return I != X.I; } 450 451 const LabelDecl *getLabel() const { 452 return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl(); 453 } 454 455 const CFGBlock *getBlock() const { 456 return *I; 457 } 458 }; 459 460 iterator begin() { return iterator(DispatchBlock.succ_begin()); } 461 iterator end() { return iterator(DispatchBlock.succ_end()); } 462 463 ExplodedNode *generateNode(const iterator &I, 464 ProgramStateRef State, 465 bool isSink = false); 466 467 const Expr *getTarget() const { return E; } 468 469 ProgramStateRef getState() const { return Pred->State; } 470 471 const LocationContext *getLocationContext() const { 472 return Pred->getLocationContext(); 473 } 474}; 475 476class SwitchNodeBuilder { 477 CoreEngine& Eng; 478 const CFGBlock *Src; 479 const Expr *Condition; 480 ExplodedNode *Pred; 481 482public: 483 SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 484 const Expr *condition, CoreEngine* eng) 485 : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} 486 487 class iterator { 488 CFGBlock::const_succ_reverse_iterator I; 489 490 friend class SwitchNodeBuilder; 491 iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} 492 493 public: 494 iterator &operator++() { ++I; return *this; } 495 bool operator!=(const iterator &X) const { return I != X.I; } 496 bool operator==(const iterator &X) const { return I == X.I; } 497 498 const CaseStmt *getCase() const { 499 return llvm::cast<CaseStmt>((*I)->getLabel()); 500 } 501 502 const CFGBlock *getBlock() const { 503 return *I; 504 } 505 }; 506 507 iterator begin() { return iterator(Src->succ_rbegin()+1); } 508 iterator end() { return iterator(Src->succ_rend()); } 509 510 const SwitchStmt *getSwitch() const { 511 return llvm::cast<SwitchStmt>(Src->getTerminator()); 512 } 513 514 ExplodedNode *generateCaseStmtNode(const iterator &I, 515 ProgramStateRef State); 516 517 ExplodedNode *generateDefaultCaseNode(ProgramStateRef State, 518 bool isSink = false); 519 520 const Expr *getCondition() const { return Condition; } 521 522 ProgramStateRef getState() const { return Pred->State; } 523 524 const LocationContext *getLocationContext() const { 525 return Pred->getLocationContext(); 526 } 527}; 528 529} // end ento namespace 530} // end clang namespace 531 532#endif 533