blob: 87472472fdeebcf6d2a2e9ee85869725f72a96bb [file] [log] [blame]
Ted Kremenekaf337412008-11-12 19:24:17 +00001//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-//
Mike Stump1eb44332009-09-09 15:08:12 +00002//
Ted Kremenekf24af5b2008-01-14 23:24:37 +00003// 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 engine.
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek4d4dd852008-02-13 17:41:41 +000015#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
Zhongxing Xu0111f572009-08-06 10:00:15 +000016#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenekf24af5b2008-01-14 23:24:37 +000017#include "clang/AST/Expr.h"
18#include "llvm/Support/Compiler.h"
19#include "llvm/Support/Casting.h"
20#include "llvm/ADT/DenseMap.h"
21#include <vector>
Ted Kremeneke1efd4d2008-12-16 22:13:33 +000022#include <queue>
Ted Kremenekf24af5b2008-01-14 23:24:37 +000023
24using llvm::cast;
25using llvm::isa;
26using namespace clang;
27
Ted Kremeneke1efd4d2008-12-16 22:13:33 +000028//===----------------------------------------------------------------------===//
29// Worklist classes for exploration of reachable states.
30//===----------------------------------------------------------------------===//
31
Ted Kremenekf24af5b2008-01-14 23:24:37 +000032namespace {
Zhongxing Xu785d29d2009-07-15 09:04:01 +000033class VISIBILITY_HIDDEN DFS : public GRWorkList {
Ted Kremenekf24af5b2008-01-14 23:24:37 +000034 llvm::SmallVector<GRWorkListUnit,20> Stack;
35public:
36 virtual bool hasWork() const {
37 return !Stack.empty();
38 }
39
40 virtual void Enqueue(const GRWorkListUnit& U) {
41 Stack.push_back(U);
42 }
43
44 virtual GRWorkListUnit Dequeue() {
45 assert (!Stack.empty());
46 const GRWorkListUnit& U = Stack.back();
47 Stack.pop_back(); // This technically "invalidates" U, but we are fine.
48 return U;
49 }
50};
Mike Stump1eb44332009-09-09 15:08:12 +000051
Ted Kremenek8ff59e82009-05-01 22:18:46 +000052class VISIBILITY_HIDDEN BFS : public GRWorkList {
53 std::queue<GRWorkListUnit> Queue;
54public:
55 virtual bool hasWork() const {
56 return !Queue.empty();
57 }
Mike Stump1eb44332009-09-09 15:08:12 +000058
Ted Kremenek8ff59e82009-05-01 22:18:46 +000059 virtual void Enqueue(const GRWorkListUnit& U) {
60 Queue.push(U);
61 }
Mike Stump1eb44332009-09-09 15:08:12 +000062
Ted Kremenek8ff59e82009-05-01 22:18:46 +000063 virtual GRWorkListUnit Dequeue() {
64 // Don't use const reference. The subsequent pop_back() might make it
65 // unsafe.
Mike Stump1eb44332009-09-09 15:08:12 +000066 GRWorkListUnit U = Queue.front();
Ted Kremenek8ff59e82009-05-01 22:18:46 +000067 Queue.pop();
68 return U;
69 }
70};
Mike Stump1eb44332009-09-09 15:08:12 +000071
Ted Kremenekf24af5b2008-01-14 23:24:37 +000072} // end anonymous namespace
73
Ted Kremenekee985462008-01-16 18:18:48 +000074// Place the dstor for GRWorkList here because it contains virtual member
75// functions, and we the code for the dstor generated in one compilation unit.
76GRWorkList::~GRWorkList() {}
77
Ted Kremenek8ff59e82009-05-01 22:18:46 +000078GRWorkList *GRWorkList::MakeDFS() { return new DFS(); }
79GRWorkList *GRWorkList::MakeBFS() { return new BFS(); }
Ted Kremenekf24af5b2008-01-14 23:24:37 +000080
Ted Kremeneke1efd4d2008-12-16 22:13:33 +000081namespace {
82 class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList {
83 std::queue<GRWorkListUnit> Queue;
84 llvm::SmallVector<GRWorkListUnit,20> Stack;
85 public:
86 virtual bool hasWork() const {
87 return !Queue.empty() || !Stack.empty();
88 }
Mike Stump1eb44332009-09-09 15:08:12 +000089
Ted Kremeneke1efd4d2008-12-16 22:13:33 +000090 virtual void Enqueue(const GRWorkListUnit& U) {
91 if (isa<BlockEntrance>(U.getNode()->getLocation()))
92 Queue.push(U);
93 else
94 Stack.push_back(U);
95 }
Mike Stump1eb44332009-09-09 15:08:12 +000096
Ted Kremeneke1efd4d2008-12-16 22:13:33 +000097 virtual GRWorkListUnit Dequeue() {
98 // Process all basic blocks to completion.
99 if (!Stack.empty()) {
100 const GRWorkListUnit& U = Stack.back();
101 Stack.pop_back(); // This technically "invalidates" U, but we are fine.
102 return U;
103 }
Mike Stump1eb44332009-09-09 15:08:12 +0000104
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000105 assert(!Queue.empty());
106 // Don't use const reference. The subsequent pop_back() might make it
107 // unsafe.
Mike Stump1eb44332009-09-09 15:08:12 +0000108 GRWorkListUnit U = Queue.front();
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000109 Queue.pop();
Mike Stump1eb44332009-09-09 15:08:12 +0000110 return U;
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000111 }
112 };
113} // end anonymous namespace
114
115GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
116 return new BFSBlockDFSContents();
117}
118
119//===----------------------------------------------------------------------===//
120// Core analysis engine.
121//===----------------------------------------------------------------------===//
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000122void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) {
Zhongxing Xu0111f572009-08-06 10:00:15 +0000123 SubEngine.ProcessEndPath(Builder);
124}
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000125
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000126void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) {
Zhongxing Xu0111f572009-08-06 10:00:15 +0000127 SubEngine.ProcessStmt(S, Builder);
128}
129
130bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
Mike Stump1eb44332009-09-09 15:08:12 +0000131 GRBlockCounter BC) {
Zhongxing Xu0111f572009-08-06 10:00:15 +0000132 return SubEngine.ProcessBlockEntrance(Blk, State, BC);
133}
134
135void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator,
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000136 GRBranchNodeBuilder& Builder) {
Mike Stump1eb44332009-09-09 15:08:12 +0000137 SubEngine.ProcessBranch(Condition, Terminator, Builder);
Zhongxing Xu0111f572009-08-06 10:00:15 +0000138}
139
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000140void GRCoreEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder) {
Zhongxing Xu0111f572009-08-06 10:00:15 +0000141 SubEngine.ProcessIndirectGoto(Builder);
142}
143
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000144void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) {
Zhongxing Xu0111f572009-08-06 10:00:15 +0000145 SubEngine.ProcessSwitch(Builder);
146}
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000147
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000148/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000149bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
Mike Stump1eb44332009-09-09 15:08:12 +0000150
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000151 if (G->num_roots() == 0) { // Initialize the analysis by constructing
152 // the root if none exists.
Mike Stump1eb44332009-09-09 15:08:12 +0000153
Zhongxing Xucc025532009-08-25 03:33:41 +0000154 CFGBlock* Entry = &(L->getCFG()->getEntry());
Mike Stump1eb44332009-09-09 15:08:12 +0000155
156 assert (Entry->empty() &&
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000157 "Entry block must be empty.");
Mike Stump1eb44332009-09-09 15:08:12 +0000158
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000159 assert (Entry->succ_size() == 1 &&
160 "Entry block must have 1 successor.");
Mike Stump1eb44332009-09-09 15:08:12 +0000161
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000162 // Get the solitary successor.
Mike Stump1eb44332009-09-09 15:08:12 +0000163 CFGBlock* Succ = *(Entry->succ_begin());
164
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000165 // Construct an edge representing the
166 // starting location in the function.
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000167 BlockEdge StartLoc(Entry, Succ, L);
Mike Stump1eb44332009-09-09 15:08:12 +0000168
Ted Kremenek8e49dd62008-02-12 18:08:17 +0000169 // Set the current block counter to being empty.
170 WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
Mike Stump1eb44332009-09-09 15:08:12 +0000171
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000172 // Generate the root.
Zhongxing Xu17fd8632009-08-17 06:19:58 +0000173 GenerateNode(StartLoc, getInitialState(L), 0);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000174 }
Mike Stump1eb44332009-09-09 15:08:12 +0000175
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000176 while (Steps && WList->hasWork()) {
177 --Steps;
178 const GRWorkListUnit& WU = WList->Dequeue();
Mike Stump1eb44332009-09-09 15:08:12 +0000179
Ted Kremenek8e49dd62008-02-12 18:08:17 +0000180 // Set the current block counter.
181 WList->setBlockCounter(WU.getBlockCounter());
182
183 // Retrieve the node.
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000184 ExplodedNode* Node = WU.getNode();
Mike Stump1eb44332009-09-09 15:08:12 +0000185
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000186 // Dispatch on the location type.
187 switch (Node->getLocation().getKind()) {
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000188 case ProgramPoint::BlockEdgeKind:
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000189 HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
190 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000191
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000192 case ProgramPoint::BlockEntranceKind:
193 HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
194 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000195
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000196 case ProgramPoint::BlockExitKind:
Ted Kremenek425c08c2008-01-15 00:24:08 +0000197 assert (false && "BlockExit location never occur in forward analysis.");
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000198 break;
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000199
200 default:
201 assert(isa<PostStmt>(Node->getLocation()));
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000202 HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
203 WU.getIndex(), Node);
Mike Stump1eb44332009-09-09 15:08:12 +0000204 break;
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000205 }
206 }
Mike Stump1eb44332009-09-09 15:08:12 +0000207
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000208 return WList->hasWork();
209}
210
Zhongxing Xu0111f572009-08-06 10:00:15 +0000211
212void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
Mike Stump1eb44332009-09-09 15:08:12 +0000213
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000214 CFGBlock* Blk = L.getDst();
Mike Stump1eb44332009-09-09 15:08:12 +0000215
216 // Check if we are entering the EXIT block.
Zhongxing Xucc025532009-08-25 03:33:41 +0000217 if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) {
Mike Stump1eb44332009-09-09 15:08:12 +0000218
219 assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0
Ted Kremenekcb48b9c2008-01-29 00:33:40 +0000220 && "EXIT block cannot contain Stmts.");
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000221
Ted Kremenek11062b12008-04-11 22:03:04 +0000222 // Process the final state transition.
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000223 GREndPathNodeBuilder Builder(Blk, Pred, this);
Ted Kremenek11062b12008-04-11 22:03:04 +0000224 ProcessEndPath(Builder);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000225
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000226 // This path is done. Don't enqueue any more nodes.
227 return;
228 }
Ted Kremenek6a6719a2008-02-29 20:27:50 +0000229
230 // FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
Mike Stump1eb44332009-09-09 15:08:12 +0000231
Ted Kremenek6a6719a2008-02-29 20:27:50 +0000232 if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000233 GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000234}
235
Zhongxing Xu0111f572009-08-06 10:00:15 +0000236void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000237 ExplodedNode* Pred) {
Mike Stump1eb44332009-09-09 15:08:12 +0000238
Ted Kremenek8e49dd62008-02-12 18:08:17 +0000239 // Increment the block counter.
240 GRBlockCounter Counter = WList->getBlockCounter();
241 Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID());
242 WList->setBlockCounter(Counter);
Mike Stump1eb44332009-09-09 15:08:12 +0000243
244 // Process the entrance of the block.
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000245 if (Stmt* S = L.getFirstStmt()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000246 GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000247 SubEngine.getStateManager());
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000248 ProcessStmt(S, Builder);
249 }
Mike Stump1eb44332009-09-09 15:08:12 +0000250 else
Ted Kremenek425c08c2008-01-15 00:24:08 +0000251 HandleBlockExit(L.getBlock(), Pred);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000252}
253
Zhongxing Xu0111f572009-08-06 10:00:15 +0000254void GRCoreEngine::HandleBlockExit(CFGBlock * B, ExplodedNode* Pred) {
Mike Stump1eb44332009-09-09 15:08:12 +0000255
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000256 if (Stmt* Term = B->getTerminator()) {
257 switch (Term->getStmtClass()) {
258 default:
259 assert(false && "Analysis for this terminator not implemented.");
260 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000261
Ted Kremenekf8108692008-02-12 21:51:20 +0000262 case Stmt::BinaryOperatorClass: // '&&' and '||'
263 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
264 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Ted Kremenekf233d482008-02-05 00:26:40 +0000266 case Stmt::ConditionalOperatorClass:
267 HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred);
Ted Kremenekf8108692008-02-12 21:51:20 +0000268 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000269
Ted Kremenekf8108692008-02-12 21:51:20 +0000270 // FIXME: Use constant-folding in CFG construction to simplify this
271 // case.
Mike Stump1eb44332009-09-09 15:08:12 +0000272
Ted Kremenekf233d482008-02-05 00:26:40 +0000273 case Stmt::ChooseExprClass:
274 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
Ted Kremenekf8108692008-02-12 21:51:20 +0000275 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000276
Ted Kremenekf8108692008-02-12 21:51:20 +0000277 case Stmt::DoStmtClass:
278 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
279 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000280
Ted Kremenekf8108692008-02-12 21:51:20 +0000281 case Stmt::ForStmtClass:
282 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
283 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000284
Ted Kremeneka58e8332008-02-13 16:56:51 +0000285 case Stmt::ContinueStmtClass:
286 case Stmt::BreakStmtClass:
Mike Stump1eb44332009-09-09 15:08:12 +0000287 case Stmt::GotoStmtClass:
Ted Kremenekf233d482008-02-05 00:26:40 +0000288 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000289
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000290 case Stmt::IfStmtClass:
291 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
Ted Kremenekf8108692008-02-12 21:51:20 +0000292 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000293
Ted Kremenek754607e2008-02-13 00:24:44 +0000294 case Stmt::IndirectGotoStmtClass: {
295 // Only 1 successor: the indirect goto dispatch block.
296 assert (B->succ_size() == 1);
Mike Stump1eb44332009-09-09 15:08:12 +0000297
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000298 GRIndirectGotoNodeBuilder
Ted Kremenek754607e2008-02-13 00:24:44 +0000299 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
300 *(B->succ_begin()), this);
Mike Stump1eb44332009-09-09 15:08:12 +0000301
Ted Kremenek754607e2008-02-13 00:24:44 +0000302 ProcessIndirectGoto(builder);
303 return;
304 }
Mike Stump1eb44332009-09-09 15:08:12 +0000305
Ted Kremenekaf337412008-11-12 19:24:17 +0000306 case Stmt::ObjCForCollectionStmtClass: {
307 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
308 //
309 // (1) inside a basic block, which represents the binding of the
310 // 'element' variable to a value.
311 // (2) in a terminator, which represents the branch.
312 //
313 // For (1), subengines will bind a value (i.e., 0 or 1) indicating
314 // whether or not collection contains any more elements. We cannot
315 // just test to see if the element is nil because a container can
316 // contain nil elements.
317 HandleBranch(Term, Term, B, Pred);
318 return;
319 }
Mike Stump1eb44332009-09-09 15:08:12 +0000320
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000321 case Stmt::SwitchStmtClass: {
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000322 GRSwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
323 this);
Mike Stump1eb44332009-09-09 15:08:12 +0000324
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000325 ProcessSwitch(builder);
326 return;
327 }
Mike Stump1eb44332009-09-09 15:08:12 +0000328
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000329 case Stmt::WhileStmtClass:
330 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
Ted Kremenekf8108692008-02-12 21:51:20 +0000331 return;
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000332 }
333 }
Ted Kremenekf8108692008-02-12 21:51:20 +0000334
335 assert (B->succ_size() == 1 &&
336 "Blocks with no terminator should have at most 1 successor.");
Mike Stump1eb44332009-09-09 15:08:12 +0000337
338 GenerateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000339 Pred->State, Pred);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000340}
341
Zhongxing Xu0111f572009-08-06 10:00:15 +0000342void GRCoreEngine::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B,
343 ExplodedNode* Pred) {
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000344 assert (B->succ_size() == 2);
345
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000346 GRBranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
347 Pred, this);
Mike Stump1eb44332009-09-09 15:08:12 +0000348
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000349 ProcessBranch(Cond, Term, Builder);
350}
351
Zhongxing Xu0111f572009-08-06 10:00:15 +0000352void GRCoreEngine::HandlePostStmt(const PostStmt& L, CFGBlock* B,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000353 unsigned StmtIdx, ExplodedNode* Pred) {
Mike Stump1eb44332009-09-09 15:08:12 +0000354
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000355 assert (!B->empty());
356
Ted Kremenek425c08c2008-01-15 00:24:08 +0000357 if (StmtIdx == B->size())
358 HandleBlockExit(B, Pred);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000359 else {
Mike Stump1eb44332009-09-09 15:08:12 +0000360 GRStmtNodeBuilder Builder(B, StmtIdx, Pred, this,
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000361 SubEngine.getStateManager());
Ted Kremenek160760e2008-01-16 22:13:19 +0000362 ProcessStmt((*B)[StmtIdx], Builder);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000363 }
364}
365
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000366/// GenerateNode - Utility method to generate nodes, hook up successors,
367/// and add nodes to the worklist.
Mike Stump1eb44332009-09-09 15:08:12 +0000368void GRCoreEngine::GenerateNode(const ProgramPoint& Loc,
Zhongxing Xu0111f572009-08-06 10:00:15 +0000369 const GRState* State, ExplodedNode* Pred) {
Mike Stump1eb44332009-09-09 15:08:12 +0000370
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000371 bool IsNew;
Zhongxing Xu38b02b92009-08-06 06:28:40 +0000372 ExplodedNode* Node = G->getNode(Loc, State, &IsNew);
Mike Stump1eb44332009-09-09 15:08:12 +0000373
374 if (Pred)
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000375 Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor.
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000376 else {
377 assert (IsNew);
378 G->addRoot(Node); // 'Node' has no predecessor. Make it a root.
379 }
Mike Stump1eb44332009-09-09 15:08:12 +0000380
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000381 // Only add 'Node' to the worklist if it was freshly generated.
Ted Kremenek8e49dd62008-02-12 18:08:17 +0000382 if (IsNew) WList->Enqueue(Node);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000383}
384
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000385GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx,
386 ExplodedNode* N, GRCoreEngine* e,
387 GRStateManager &mgr)
Mike Stump1eb44332009-09-09 15:08:12 +0000388 : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0),
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000389 PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
390 PointKind(ProgramPoint::PostStmtKind), Tag(0) {
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000391 Deferred.insert(N);
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000392 CleanedState = getLastNode()->getState();
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000393}
394
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000395GRStmtNodeBuilder::~GRStmtNodeBuilder() {
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000396 for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
Ted Kremenekb38911f2008-01-30 23:03:39 +0000397 if (!(*I)->isSink())
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000398 GenerateAutoTransition(*I);
399}
400
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000401void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Ted Kremenekb38911f2008-01-30 23:03:39 +0000402 assert (!N->isSink());
Mike Stump1eb44332009-09-09 15:08:12 +0000403
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000404 PostStmt Loc(getStmt(), N->getLocationContext());
Mike Stump1eb44332009-09-09 15:08:12 +0000405
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000406 if (Loc == N->getLocation()) {
407 // Note: 'N' should be a fresh node because otherwise it shouldn't be
408 // a member of Deferred.
409 Eng.WList->Enqueue(N, B, Idx+1);
410 return;
411 }
Mike Stump1eb44332009-09-09 15:08:12 +0000412
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000413 bool IsNew;
Zhongxing Xu38b02b92009-08-06 06:28:40 +0000414 ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew);
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000415 Succ->addPredecessor(N, *Eng.G);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000416
417 if (IsNew)
418 Eng.WList->Enqueue(Succ, B, Idx+1);
419}
420
Ted Kremenek5f85e172009-07-22 22:35:28 +0000421static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K,
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000422 const LocationContext *L, const void *tag) {
Ted Kremenek331b0ac2008-06-18 05:34:07 +0000423 switch (K) {
424 default:
425 assert(false && "Invalid PostXXXKind.");
Mike Stump1eb44332009-09-09 15:08:12 +0000426
Ted Kremenek331b0ac2008-06-18 05:34:07 +0000427 case ProgramPoint::PostStmtKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000428 return PostStmt(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000429
Ted Kremenek331b0ac2008-06-18 05:34:07 +0000430 case ProgramPoint::PostLoadKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000431 return PostLoad(S, L, tag);
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000432
433 case ProgramPoint::PostUndefLocationCheckFailedKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000434 return PostUndefLocationCheckFailed(S, L, tag);
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000435
436 case ProgramPoint::PostLocationChecksSucceedKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000437 return PostLocationChecksSucceed(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000438
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000439 case ProgramPoint::PostOutOfBoundsCheckFailedKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000440 return PostOutOfBoundsCheckFailed(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000441
Ted Kremeneke1efd4d2008-12-16 22:13:33 +0000442 case ProgramPoint::PostNullCheckFailedKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000443 return PostNullCheckFailed(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000444
Ted Kremenekbf4e4192008-10-17 20:49:23 +0000445 case ProgramPoint::PostStoreKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000446 return PostStore(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000447
Ted Kremenek7090d542009-05-07 18:27:16 +0000448 case ProgramPoint::PostLValueKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000449 return PostLValue(S, L, tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000450
Ted Kremenek331b0ac2008-06-18 05:34:07 +0000451 case ProgramPoint::PostPurgeDeadSymbolsKind:
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000452 return PostPurgeDeadSymbols(S, L, tag);
Ted Kremenek331b0ac2008-06-18 05:34:07 +0000453 }
454}
455
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000456ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000457GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000458 ExplodedNode* Pred,
Ted Kremenek1670e402009-04-11 00:11:10 +0000459 ProgramPoint::Kind K,
460 const void *tag) {
Ted Kremeneke01ac572009-07-22 21:40:46 +0000461 return K == ProgramPoint::PreStmtKind
Mike Stump1eb44332009-09-09 15:08:12 +0000462 ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag),
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000463 State, Pred)
464 : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag),
Mike Stump1eb44332009-09-09 15:08:12 +0000465 State, Pred);
Ted Kremenek58e899b2009-02-19 23:45:28 +0000466}
467
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000468ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000469GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
Zhongxing Xu38b02b92009-08-06 06:28:40 +0000470 const GRState* State,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000471 ExplodedNode* Pred) {
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000472 bool IsNew;
Zhongxing Xu38b02b92009-08-06 06:28:40 +0000473 ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew);
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000474 N->addPredecessor(Pred, *Eng.G);
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000475 Deferred.erase(Pred);
Mike Stump1eb44332009-09-09 15:08:12 +0000476
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000477 if (IsNew) {
478 Deferred.insert(N);
479 LastNode = N;
480 return N;
481 }
Mike Stump1eb44332009-09-09 15:08:12 +0000482
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000483 LastNode = NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000484 return NULL;
Ted Kremenekf24af5b2008-01-14 23:24:37 +0000485}
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000486
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000487ExplodedNode* GRBranchNodeBuilder::generateNode(const GRState* State,
488 bool branch) {
Mike Stump1eb44332009-09-09 15:08:12 +0000489
Ted Kremenek52003542009-07-20 18:44:36 +0000490 // If the branch has been marked infeasible we should not generate a node.
491 if (!isFeasible(branch))
492 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000493
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000494 bool IsNew;
Mike Stump1eb44332009-09-09 15:08:12 +0000495
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000496 ExplodedNode* Succ =
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000497 Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
498 State, &IsNew);
Mike Stump1eb44332009-09-09 15:08:12 +0000499
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000500 Succ->addPredecessor(Pred, *Eng.G);
Mike Stump1eb44332009-09-09 15:08:12 +0000501
Ted Kremenek52003542009-07-20 18:44:36 +0000502 if (branch)
503 GeneratedTrue = true;
504 else
Mike Stump1eb44332009-09-09 15:08:12 +0000505 GeneratedFalse = true;
506
Ted Kremenekb38911f2008-01-30 23:03:39 +0000507 if (IsNew) {
Ted Kremenek3b4f6702008-01-30 23:24:39 +0000508 Deferred.push_back(Succ);
Ted Kremenekb38911f2008-01-30 23:03:39 +0000509 return Succ;
510 }
Mike Stump1eb44332009-09-09 15:08:12 +0000511
Ted Kremenekb38911f2008-01-30 23:03:39 +0000512 return NULL;
Ted Kremenek7d7fe6d2008-01-29 22:56:11 +0000513}
Ted Kremenek71c29bd2008-01-29 23:32:35 +0000514
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000515GRBranchNodeBuilder::~GRBranchNodeBuilder() {
516 if (!GeneratedTrue) generateNode(Pred->State, true);
517 if (!GeneratedFalse) generateNode(Pred->State, false);
Mike Stump1eb44332009-09-09 15:08:12 +0000518
Ted Kremenek3b4f6702008-01-30 23:24:39 +0000519 for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
Ted Kremenek8e49dd62008-02-12 18:08:17 +0000520 if (!(*I)->isSink()) Eng.WList->Enqueue(*I);
Ted Kremenek71c29bd2008-01-29 23:32:35 +0000521}
Ted Kremenek754607e2008-02-13 00:24:44 +0000522
Ted Kremenek754607e2008-02-13 00:24:44 +0000523
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000524ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000525GRIndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
526 bool isSink) {
Ted Kremenek754607e2008-02-13 00:24:44 +0000527 bool IsNew;
Mike Stump1eb44332009-09-09 15:08:12 +0000528
529 ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000530 Pred->getLocationContext()), St, &IsNew);
Mike Stump1eb44332009-09-09 15:08:12 +0000531
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000532 Succ->addPredecessor(Pred, *Eng.G);
Mike Stump1eb44332009-09-09 15:08:12 +0000533
Ted Kremenek754607e2008-02-13 00:24:44 +0000534 if (IsNew) {
Mike Stump1eb44332009-09-09 15:08:12 +0000535
Ted Kremenek754607e2008-02-13 00:24:44 +0000536 if (isSink)
537 Succ->markAsSink();
538 else
539 Eng.WList->Enqueue(Succ);
Mike Stump1eb44332009-09-09 15:08:12 +0000540
Ted Kremenek754607e2008-02-13 00:24:44 +0000541 return Succ;
542 }
Mike Stump1eb44332009-09-09 15:08:12 +0000543
Ted Kremenek754607e2008-02-13 00:24:44 +0000544 return NULL;
545}
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000546
547
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000548ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000549GRSwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000550
551 bool IsNew;
Mike Stump1eb44332009-09-09 15:08:12 +0000552
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000553 ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
554 Pred->getLocationContext()), St, &IsNew);
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000555 Succ->addPredecessor(Pred, *Eng.G);
Mike Stump1eb44332009-09-09 15:08:12 +0000556
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000557 if (IsNew) {
558 Eng.WList->Enqueue(Succ);
559 return Succ;
560 }
Mike Stump1eb44332009-09-09 15:08:12 +0000561
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000562 return NULL;
563}
564
565
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000566ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000567GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
Mike Stump1eb44332009-09-09 15:08:12 +0000568
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000569 // Get the block for the default case.
570 assert (Src->succ_rbegin() != Src->succ_rend());
571 CFGBlock* DefaultBlock = *Src->succ_rbegin();
Mike Stump1eb44332009-09-09 15:08:12 +0000572
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000573 bool IsNew;
Mike Stump1eb44332009-09-09 15:08:12 +0000574
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000575 ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
576 Pred->getLocationContext()), St, &IsNew);
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000577 Succ->addPredecessor(Pred, *Eng.G);
Mike Stump1eb44332009-09-09 15:08:12 +0000578
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000579 if (IsNew) {
580 if (isSink)
581 Succ->markAsSink();
582 else
583 Eng.WList->Enqueue(Succ);
Mike Stump1eb44332009-09-09 15:08:12 +0000584
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000585 return Succ;
586 }
Mike Stump1eb44332009-09-09 15:08:12 +0000587
Ted Kremenekdaeb9a72008-02-13 23:08:21 +0000588 return NULL;
589}
Ted Kremenek11062b12008-04-11 22:03:04 +0000590
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000591GREndPathNodeBuilder::~GREndPathNodeBuilder() {
Ted Kremenek11062b12008-04-11 22:03:04 +0000592 // Auto-generate an EOP node if one has not been generated.
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000593 if (!HasGeneratedNode) generateNode(Pred->State);
Ted Kremenek11062b12008-04-11 22:03:04 +0000594}
595
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000596ExplodedNode*
Zhongxing Xu031ccc02009-08-06 12:48:26 +0000597GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
598 ExplodedNode* P) {
Mike Stump1eb44332009-09-09 15:08:12 +0000599 HasGeneratedNode = true;
Ted Kremenek11062b12008-04-11 22:03:04 +0000600 bool IsNew;
Mike Stump1eb44332009-09-09 15:08:12 +0000601
602 ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
Zhongxing Xu25e695b2009-08-15 03:17:38 +0000603 Pred->getLocationContext(), tag), State, &IsNew);
Mike Stump1eb44332009-09-09 15:08:12 +0000604
Ted Kremenek5fe4d9d2009-10-07 00:42:52 +0000605 Node->addPredecessor(P ? P : Pred, *Eng.G);
Mike Stump1eb44332009-09-09 15:08:12 +0000606
Ted Kremenek11062b12008-04-11 22:03:04 +0000607 if (IsNew) {
Ted Kremenek11062b12008-04-11 22:03:04 +0000608 Eng.G->addEndOfPath(Node);
Ted Kremenek4f285152008-04-18 16:30:14 +0000609 return Node;
Ted Kremenek11062b12008-04-11 22:03:04 +0000610 }
Mike Stump1eb44332009-09-09 15:08:12 +0000611
Ted Kremenek4f285152008-04-18 16:30:14 +0000612 return NULL;
Ted Kremenek11062b12008-04-11 22:03:04 +0000613}