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