clang API Documentation
00001 //==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a generic engine for intraprocedural, path-sensitive, 00011 // dataflow analysis via graph reachability. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H 00016 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H 00017 00018 #include "clang/AST/Expr.h" 00019 #include "clang/Analysis/AnalysisContext.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 00022 #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" 00023 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" 00024 #include <memory> 00025 00026 namespace clang { 00027 00028 class ProgramPointTag; 00029 00030 namespace ento { 00031 00032 class NodeBuilder; 00033 00034 //===----------------------------------------------------------------------===// 00035 /// CoreEngine - Implements the core logic of the graph-reachability 00036 /// analysis. It traverses the CFG and generates the ExplodedGraph. 00037 /// Program "states" are treated as opaque void pointers. 00038 /// The template class CoreEngine (which subclasses CoreEngine) 00039 /// provides the matching component to the engine that knows the actual types 00040 /// for states. Note that this engine only dispatches to transfer functions 00041 /// at the statement and block-level. The analyses themselves must implement 00042 /// any transfer function logic and the sub-expression level (if any). 00043 class CoreEngine { 00044 friend struct NodeBuilderContext; 00045 friend class NodeBuilder; 00046 friend class ExprEngine; 00047 friend class CommonNodeBuilder; 00048 friend class IndirectGotoNodeBuilder; 00049 friend class SwitchNodeBuilder; 00050 friend class EndOfFunctionNodeBuilder; 00051 public: 00052 typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > 00053 BlocksExhausted; 00054 00055 typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > 00056 BlocksAborted; 00057 00058 private: 00059 00060 SubEngine& SubEng; 00061 00062 /// G - The simulation graph. Each node is a (location,state) pair. 00063 mutable ExplodedGraph G; 00064 00065 /// WList - A set of queued nodes that need to be processed by the 00066 /// worklist algorithm. It is up to the implementation of WList to decide 00067 /// the order that nodes are processed. 00068 std::unique_ptr<WorkList> WList; 00069 00070 /// BCounterFactory - A factory object for created BlockCounter objects. 00071 /// These are used to record for key nodes in the ExplodedGraph the 00072 /// number of times different CFGBlocks have been visited along a path. 00073 BlockCounter::Factory BCounterFactory; 00074 00075 /// The locations where we stopped doing work because we visited a location 00076 /// too many times. 00077 BlocksExhausted blocksExhausted; 00078 00079 /// The locations where we stopped because the engine aborted analysis, 00080 /// usually because it could not reason about something. 00081 BlocksAborted blocksAborted; 00082 00083 /// The information about functions shared by the whole translation unit. 00084 /// (This data is owned by AnalysisConsumer.) 00085 FunctionSummariesTy *FunctionSummaries; 00086 00087 void generateNode(const ProgramPoint &Loc, 00088 ProgramStateRef State, 00089 ExplodedNode *Pred); 00090 00091 void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); 00092 void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); 00093 void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); 00094 void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); 00095 00096 void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, 00097 ExplodedNode *Pred); 00098 void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, 00099 const CFGBlock *B, ExplodedNode *Pred); 00100 00101 /// Handle conditional logic for running static initializers. 00102 void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, 00103 ExplodedNode *Pred); 00104 00105 private: 00106 CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION; 00107 void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION; 00108 00109 ExplodedNode *generateCallExitBeginNode(ExplodedNode *N); 00110 00111 public: 00112 /// Construct a CoreEngine object to analyze the provided CFG. 00113 CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS) 00114 : SubEng(subengine), WList(WorkList::makeDFS()), 00115 BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {} 00116 00117 /// getGraph - Returns the exploded graph. 00118 ExplodedGraph &getGraph() { return G; } 00119 00120 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of 00121 /// steps. Returns true if there is still simulation state on the worklist. 00122 bool ExecuteWorkList(const LocationContext *L, unsigned Steps, 00123 ProgramStateRef InitState); 00124 /// Returns true if there is still simulation state on the worklist. 00125 bool ExecuteWorkListWithInitialState(const LocationContext *L, 00126 unsigned Steps, 00127 ProgramStateRef InitState, 00128 ExplodedNodeSet &Dst); 00129 00130 /// Dispatch the work list item based on the given location information. 00131 /// Use Pred parameter as the predecessor state. 00132 void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, 00133 const WorkListUnit& WU); 00134 00135 // Functions for external checking of whether we have unfinished work 00136 bool wasBlockAborted() const { return !blocksAborted.empty(); } 00137 bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } 00138 bool hasWorkRemaining() const { return wasBlocksExhausted() || 00139 WList->hasWork() || 00140 wasBlockAborted(); } 00141 00142 /// Inform the CoreEngine that a basic block was aborted because 00143 /// it could not be completely analyzed. 00144 void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { 00145 blocksAborted.push_back(std::make_pair(block, node)); 00146 } 00147 00148 WorkList *getWorkList() const { return WList.get(); } 00149 00150 BlocksExhausted::const_iterator blocks_exhausted_begin() const { 00151 return blocksExhausted.begin(); 00152 } 00153 BlocksExhausted::const_iterator blocks_exhausted_end() const { 00154 return blocksExhausted.end(); 00155 } 00156 BlocksAborted::const_iterator blocks_aborted_begin() const { 00157 return blocksAborted.begin(); 00158 } 00159 BlocksAborted::const_iterator blocks_aborted_end() const { 00160 return blocksAborted.end(); 00161 } 00162 00163 /// \brief Enqueue the given set of nodes onto the work list. 00164 void enqueue(ExplodedNodeSet &Set); 00165 00166 /// \brief Enqueue nodes that were created as a result of processing 00167 /// a statement onto the work list. 00168 void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx); 00169 00170 /// \brief enqueue the nodes corresponding to the end of function onto the 00171 /// end of path / work list. 00172 void enqueueEndOfFunction(ExplodedNodeSet &Set); 00173 00174 /// \brief Enqueue a single node created as a result of statement processing. 00175 void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); 00176 }; 00177 00178 // TODO: Turn into a calss. 00179 struct NodeBuilderContext { 00180 const CoreEngine &Eng; 00181 const CFGBlock *Block; 00182 const LocationContext *LC; 00183 NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N) 00184 : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); } 00185 00186 /// \brief Return the CFGBlock associated with this builder. 00187 const CFGBlock *getBlock() const { return Block; } 00188 00189 /// \brief Returns the number of times the current basic block has been 00190 /// visited on the exploded graph path. 00191 unsigned blockCount() const { 00192 return Eng.WList->getBlockCounter().getNumVisited( 00193 LC->getCurrentStackFrame(), 00194 Block->getBlockID()); 00195 } 00196 }; 00197 00198 /// \class NodeBuilder 00199 /// \brief This is the simplest builder which generates nodes in the 00200 /// ExplodedGraph. 00201 /// 00202 /// The main benefit of the builder is that it automatically tracks the 00203 /// frontier nodes (or destination set). This is the set of nodes which should 00204 /// be propagated to the next step / builder. They are the nodes which have been 00205 /// added to the builder (either as the input node set or as the newly 00206 /// constructed nodes) but did not have any outgoing transitions added. 00207 class NodeBuilder { 00208 virtual void anchor(); 00209 protected: 00210 const NodeBuilderContext &C; 00211 00212 /// Specifies if the builder results have been finalized. For example, if it 00213 /// is set to false, autotransitions are yet to be generated. 00214 bool Finalized; 00215 bool HasGeneratedNodes; 00216 /// \brief The frontier set - a set of nodes which need to be propagated after 00217 /// the builder dies. 00218 ExplodedNodeSet &Frontier; 00219 00220 /// Checkes if the results are ready. 00221 virtual bool checkResults() { 00222 if (!Finalized) 00223 return false; 00224 return true; 00225 } 00226 00227 bool hasNoSinksInFrontier() { 00228 for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { 00229 if ((*I)->isSink()) 00230 return false; 00231 } 00232 return true; 00233 } 00234 00235 /// Allow subclasses to finalize results before result_begin() is executed. 00236 virtual void finalizeResults() {} 00237 00238 ExplodedNode *generateNodeImpl(const ProgramPoint &PP, 00239 ProgramStateRef State, 00240 ExplodedNode *Pred, 00241 bool MarkAsSink = false); 00242 00243 public: 00244 NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 00245 const NodeBuilderContext &Ctx, bool F = true) 00246 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 00247 Frontier.Add(SrcNode); 00248 } 00249 00250 NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 00251 const NodeBuilderContext &Ctx, bool F = true) 00252 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 00253 Frontier.insert(SrcSet); 00254 assert(hasNoSinksInFrontier()); 00255 } 00256 00257 virtual ~NodeBuilder() {} 00258 00259 /// \brief Generates a node in the ExplodedGraph. 00260 ExplodedNode *generateNode(const ProgramPoint &PP, 00261 ProgramStateRef State, 00262 ExplodedNode *Pred) { 00263 return generateNodeImpl(PP, State, Pred, false); 00264 } 00265 00266 /// \brief Generates a sink in the ExplodedGraph. 00267 /// 00268 /// When a node is marked as sink, the exploration from the node is stopped - 00269 /// the node becomes the last node on the path and certain kinds of bugs are 00270 /// suppressed. 00271 ExplodedNode *generateSink(const ProgramPoint &PP, 00272 ProgramStateRef State, 00273 ExplodedNode *Pred) { 00274 return generateNodeImpl(PP, State, Pred, true); 00275 } 00276 00277 const ExplodedNodeSet &getResults() { 00278 finalizeResults(); 00279 assert(checkResults()); 00280 return Frontier; 00281 } 00282 00283 typedef ExplodedNodeSet::iterator iterator; 00284 /// \brief Iterators through the results frontier. 00285 inline iterator begin() { 00286 finalizeResults(); 00287 assert(checkResults()); 00288 return Frontier.begin(); 00289 } 00290 inline iterator end() { 00291 finalizeResults(); 00292 return Frontier.end(); 00293 } 00294 00295 const NodeBuilderContext &getContext() { return C; } 00296 bool hasGeneratedNodes() { return HasGeneratedNodes; } 00297 00298 void takeNodes(const ExplodedNodeSet &S) { 00299 for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) 00300 Frontier.erase(*I); 00301 } 00302 void takeNodes(ExplodedNode *N) { Frontier.erase(N); } 00303 void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } 00304 void addNodes(ExplodedNode *N) { Frontier.Add(N); } 00305 }; 00306 00307 /// \class NodeBuilderWithSinks 00308 /// \brief This node builder keeps track of the generated sink nodes. 00309 class NodeBuilderWithSinks: public NodeBuilder { 00310 void anchor() override; 00311 protected: 00312 SmallVector<ExplodedNode*, 2> sinksGenerated; 00313 ProgramPoint &Location; 00314 00315 public: 00316 NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, 00317 const NodeBuilderContext &Ctx, ProgramPoint &L) 00318 : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} 00319 00320 ExplodedNode *generateNode(ProgramStateRef State, 00321 ExplodedNode *Pred, 00322 const ProgramPointTag *Tag = nullptr) { 00323 const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); 00324 return NodeBuilder::generateNode(LocalLoc, State, Pred); 00325 } 00326 00327 ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, 00328 const ProgramPointTag *Tag = nullptr) { 00329 const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); 00330 ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred); 00331 if (N && N->isSink()) 00332 sinksGenerated.push_back(N); 00333 return N; 00334 } 00335 00336 const SmallVectorImpl<ExplodedNode*> &getSinks() const { 00337 return sinksGenerated; 00338 } 00339 }; 00340 00341 /// \class StmtNodeBuilder 00342 /// \brief This builder class is useful for generating nodes that resulted from 00343 /// visiting a statement. The main difference from its parent NodeBuilder is 00344 /// that it creates a statement specific ProgramPoint. 00345 class StmtNodeBuilder: public NodeBuilder { 00346 NodeBuilder *EnclosingBldr; 00347 public: 00348 00349 /// \brief Constructs a StmtNodeBuilder. If the builder is going to process 00350 /// nodes currently owned by another builder(with larger scope), use 00351 /// Enclosing builder to transfer ownership. 00352 StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 00353 const NodeBuilderContext &Ctx, 00354 NodeBuilder *Enclosing = nullptr) 00355 : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { 00356 if (EnclosingBldr) 00357 EnclosingBldr->takeNodes(SrcNode); 00358 } 00359 00360 StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 00361 const NodeBuilderContext &Ctx, 00362 NodeBuilder *Enclosing = nullptr) 00363 : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { 00364 if (EnclosingBldr) 00365 for (ExplodedNodeSet::iterator I = SrcSet.begin(), 00366 E = SrcSet.end(); I != E; ++I ) 00367 EnclosingBldr->takeNodes(*I); 00368 } 00369 00370 virtual ~StmtNodeBuilder(); 00371 00372 using NodeBuilder::generateNode; 00373 using NodeBuilder::generateSink; 00374 00375 ExplodedNode *generateNode(const Stmt *S, 00376 ExplodedNode *Pred, 00377 ProgramStateRef St, 00378 const ProgramPointTag *tag = nullptr, 00379 ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ 00380 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 00381 Pred->getLocationContext(), tag); 00382 return NodeBuilder::generateNode(L, St, Pred); 00383 } 00384 00385 ExplodedNode *generateSink(const Stmt *S, 00386 ExplodedNode *Pred, 00387 ProgramStateRef St, 00388 const ProgramPointTag *tag = nullptr, 00389 ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ 00390 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 00391 Pred->getLocationContext(), tag); 00392 return NodeBuilder::generateSink(L, St, Pred); 00393 } 00394 }; 00395 00396 /// \brief BranchNodeBuilder is responsible for constructing the nodes 00397 /// corresponding to the two branches of the if statement - true and false. 00398 class BranchNodeBuilder: public NodeBuilder { 00399 void anchor() override; 00400 const CFGBlock *DstT; 00401 const CFGBlock *DstF; 00402 00403 bool InFeasibleTrue; 00404 bool InFeasibleFalse; 00405 00406 public: 00407 BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 00408 const NodeBuilderContext &C, 00409 const CFGBlock *dstT, const CFGBlock *dstF) 00410 : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), 00411 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { 00412 // The branch node builder does not generate autotransitions. 00413 // If there are no successors it means that both branches are infeasible. 00414 takeNodes(SrcNode); 00415 } 00416 00417 BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 00418 const NodeBuilderContext &C, 00419 const CFGBlock *dstT, const CFGBlock *dstF) 00420 : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), 00421 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { 00422 takeNodes(SrcSet); 00423 } 00424 00425 ExplodedNode *generateNode(ProgramStateRef State, bool branch, 00426 ExplodedNode *Pred); 00427 00428 const CFGBlock *getTargetBlock(bool branch) const { 00429 return branch ? DstT : DstF; 00430 } 00431 00432 void markInfeasible(bool branch) { 00433 if (branch) 00434 InFeasibleTrue = true; 00435 else 00436 InFeasibleFalse = true; 00437 } 00438 00439 bool isFeasible(bool branch) { 00440 return branch ? !InFeasibleTrue : !InFeasibleFalse; 00441 } 00442 }; 00443 00444 class IndirectGotoNodeBuilder { 00445 CoreEngine& Eng; 00446 const CFGBlock *Src; 00447 const CFGBlock &DispatchBlock; 00448 const Expr *E; 00449 ExplodedNode *Pred; 00450 00451 public: 00452 IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 00453 const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) 00454 : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} 00455 00456 class iterator { 00457 CFGBlock::const_succ_iterator I; 00458 00459 friend class IndirectGotoNodeBuilder; 00460 iterator(CFGBlock::const_succ_iterator i) : I(i) {} 00461 public: 00462 00463 iterator &operator++() { ++I; return *this; } 00464 bool operator!=(const iterator &X) const { return I != X.I; } 00465 00466 const LabelDecl *getLabel() const { 00467 return cast<LabelStmt>((*I)->getLabel())->getDecl(); 00468 } 00469 00470 const CFGBlock *getBlock() const { 00471 return *I; 00472 } 00473 }; 00474 00475 iterator begin() { return iterator(DispatchBlock.succ_begin()); } 00476 iterator end() { return iterator(DispatchBlock.succ_end()); } 00477 00478 ExplodedNode *generateNode(const iterator &I, 00479 ProgramStateRef State, 00480 bool isSink = false); 00481 00482 const Expr *getTarget() const { return E; } 00483 00484 ProgramStateRef getState() const { return Pred->State; } 00485 00486 const LocationContext *getLocationContext() const { 00487 return Pred->getLocationContext(); 00488 } 00489 }; 00490 00491 class SwitchNodeBuilder { 00492 CoreEngine& Eng; 00493 const CFGBlock *Src; 00494 const Expr *Condition; 00495 ExplodedNode *Pred; 00496 00497 public: 00498 SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 00499 const Expr *condition, CoreEngine* eng) 00500 : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} 00501 00502 class iterator { 00503 CFGBlock::const_succ_reverse_iterator I; 00504 00505 friend class SwitchNodeBuilder; 00506 iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} 00507 00508 public: 00509 iterator &operator++() { ++I; return *this; } 00510 bool operator!=(const iterator &X) const { return I != X.I; } 00511 bool operator==(const iterator &X) const { return I == X.I; } 00512 00513 const CaseStmt *getCase() const { 00514 return cast<CaseStmt>((*I)->getLabel()); 00515 } 00516 00517 const CFGBlock *getBlock() const { 00518 return *I; 00519 } 00520 }; 00521 00522 iterator begin() { return iterator(Src->succ_rbegin()+1); } 00523 iterator end() { return iterator(Src->succ_rend()); } 00524 00525 const SwitchStmt *getSwitch() const { 00526 return cast<SwitchStmt>(Src->getTerminator()); 00527 } 00528 00529 ExplodedNode *generateCaseStmtNode(const iterator &I, 00530 ProgramStateRef State); 00531 00532 ExplodedNode *generateDefaultCaseNode(ProgramStateRef State, 00533 bool isSink = false); 00534 00535 const Expr *getCondition() const { return Condition; } 00536 00537 ProgramStateRef getState() const { return Pred->State; } 00538 00539 const LocationContext *getLocationContext() const { 00540 return Pred->getLocationContext(); 00541 } 00542 }; 00543 00544 } // end ento namespace 00545 } // end clang namespace 00546 00547 #endif