2008-11-13 03:24:17 +08:00
|
|
|
//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-//
|
2009-09-09 23:08:12 +08:00
|
|
|
//
|
2008-01-15 07:24:37 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines a generic engine for intraprocedural, path-sensitive,
|
|
|
|
// dataflow analysis via graph reachability engine.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-22 21:52:13 +08:00
|
|
|
#include "clang/Checker/PathSensitive/AnalysisManager.h"
|
2010-01-25 12:41:41 +08:00
|
|
|
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
|
|
|
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
2010-07-22 21:52:13 +08:00
|
|
|
#include "clang/Index/TranslationUnit.h"
|
2008-01-15 07:24:37 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include <vector>
|
2008-12-17 06:13:33 +08:00
|
|
|
#include <queue>
|
2008-01-15 07:24:37 +08:00
|
|
|
|
|
|
|
using llvm::cast;
|
|
|
|
using llvm::isa;
|
|
|
|
using namespace clang;
|
|
|
|
|
2010-07-22 21:52:13 +08:00
|
|
|
// This should be removed in the future.
|
|
|
|
namespace clang {
|
|
|
|
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
|
|
|
const LangOptions& lopts);
|
|
|
|
}
|
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Worklist classes for exploration of reachable states.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-11-13 13:04:49 +08:00
|
|
|
GRWorkList::Visitor::~Visitor() {}
|
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
namespace {
|
2009-11-28 14:07:30 +08:00
|
|
|
class DFS : public GRWorkList {
|
2008-01-15 07:24:37 +08:00
|
|
|
llvm::SmallVector<GRWorkListUnit,20> Stack;
|
|
|
|
public:
|
|
|
|
virtual bool hasWork() const {
|
|
|
|
return !Stack.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void Enqueue(const GRWorkListUnit& U) {
|
|
|
|
Stack.push_back(U);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual GRWorkListUnit Dequeue() {
|
|
|
|
assert (!Stack.empty());
|
|
|
|
const GRWorkListUnit& U = Stack.back();
|
|
|
|
Stack.pop_back(); // This technically "invalidates" U, but we are fine.
|
|
|
|
return U;
|
|
|
|
}
|
2010-11-13 13:04:49 +08:00
|
|
|
|
|
|
|
virtual bool VisitItemsInWorkList(Visitor &V) {
|
|
|
|
for (llvm::SmallVectorImpl<GRWorkListUnit>::iterator
|
|
|
|
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
|
|
|
|
if (V.Visit(*I))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2008-01-15 07:24:37 +08:00
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-28 14:07:30 +08:00
|
|
|
class BFS : public GRWorkList {
|
2010-11-13 13:04:49 +08:00
|
|
|
std::deque<GRWorkListUnit> Queue;
|
2009-05-02 06:18:46 +08:00
|
|
|
public:
|
|
|
|
virtual bool hasWork() const {
|
|
|
|
return !Queue.empty();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-02 06:18:46 +08:00
|
|
|
virtual void Enqueue(const GRWorkListUnit& U) {
|
2010-11-13 13:04:49 +08:00
|
|
|
Queue.push_front(U);
|
2009-05-02 06:18:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-02 06:18:46 +08:00
|
|
|
virtual GRWorkListUnit Dequeue() {
|
2009-09-09 23:08:12 +08:00
|
|
|
GRWorkListUnit U = Queue.front();
|
2010-11-13 13:04:49 +08:00
|
|
|
Queue.pop_front();
|
2009-05-02 06:18:46 +08:00
|
|
|
return U;
|
|
|
|
}
|
2010-11-13 13:04:49 +08:00
|
|
|
|
|
|
|
virtual bool VisitItemsInWorkList(Visitor &V) {
|
|
|
|
for (std::deque<GRWorkListUnit>::iterator
|
|
|
|
I = Queue.begin(), E = Queue.end(); I != E; ++I) {
|
|
|
|
if (V.Visit(*I))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 06:18:46 +08:00
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-01-17 02:18:48 +08:00
|
|
|
// Place the dstor for GRWorkList here because it contains virtual member
|
|
|
|
// functions, and we the code for the dstor generated in one compilation unit.
|
|
|
|
GRWorkList::~GRWorkList() {}
|
|
|
|
|
2009-05-02 06:18:46 +08:00
|
|
|
GRWorkList *GRWorkList::MakeDFS() { return new DFS(); }
|
|
|
|
GRWorkList *GRWorkList::MakeBFS() { return new BFS(); }
|
2008-01-15 07:24:37 +08:00
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
namespace {
|
2009-11-28 14:07:30 +08:00
|
|
|
class BFSBlockDFSContents : public GRWorkList {
|
2010-11-13 13:04:49 +08:00
|
|
|
std::deque<GRWorkListUnit> Queue;
|
2008-12-17 06:13:33 +08:00
|
|
|
llvm::SmallVector<GRWorkListUnit,20> Stack;
|
|
|
|
public:
|
|
|
|
virtual bool hasWork() const {
|
|
|
|
return !Queue.empty() || !Stack.empty();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
virtual void Enqueue(const GRWorkListUnit& U) {
|
|
|
|
if (isa<BlockEntrance>(U.getNode()->getLocation()))
|
2010-11-13 13:04:49 +08:00
|
|
|
Queue.push_front(U);
|
2008-12-17 06:13:33 +08:00
|
|
|
else
|
|
|
|
Stack.push_back(U);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
virtual GRWorkListUnit Dequeue() {
|
|
|
|
// Process all basic blocks to completion.
|
|
|
|
if (!Stack.empty()) {
|
|
|
|
const GRWorkListUnit& U = Stack.back();
|
|
|
|
Stack.pop_back(); // This technically "invalidates" U, but we are fine.
|
|
|
|
return U;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
assert(!Queue.empty());
|
|
|
|
// Don't use const reference. The subsequent pop_back() might make it
|
|
|
|
// unsafe.
|
2009-09-09 23:08:12 +08:00
|
|
|
GRWorkListUnit U = Queue.front();
|
2010-11-13 13:04:49 +08:00
|
|
|
Queue.pop_front();
|
2009-09-09 23:08:12 +08:00
|
|
|
return U;
|
2008-12-17 06:13:33 +08:00
|
|
|
}
|
2010-11-13 13:04:49 +08:00
|
|
|
virtual bool VisitItemsInWorkList(Visitor &V) {
|
|
|
|
for (llvm::SmallVectorImpl<GRWorkListUnit>::iterator
|
|
|
|
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
|
|
|
|
if (V.Visit(*I))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (std::deque<GRWorkListUnit>::iterator
|
|
|
|
I = Queue.begin(), E = Queue.end(); I != E; ++I) {
|
|
|
|
if (V.Visit(*I))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
|
|
|
|
return new BFSBlockDFSContents();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Core analysis engine.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2010-02-26 03:01:53 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
|
2010-07-22 21:52:13 +08:00
|
|
|
bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
|
|
|
|
const GRState *InitState) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
if (G->num_roots() == 0) { // Initialize the analysis by constructing
|
|
|
|
// the root if none exists.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const CFGBlock* Entry = &(L->getCFG()->getEntry());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
assert (Entry->empty() &&
|
2008-01-15 07:24:37 +08:00
|
|
|
"Entry block must be empty.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
assert (Entry->succ_size() == 1 &&
|
|
|
|
"Entry block must have 1 successor.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
// Get the solitary successor.
|
2010-07-20 14:22:24 +08:00
|
|
|
const CFGBlock* Succ = *(Entry->succ_begin());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
// Construct an edge representing the
|
|
|
|
// starting location in the function.
|
2009-08-15 11:17:38 +08:00
|
|
|
BlockEdge StartLoc(Entry, Succ, L);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 02:08:17 +08:00
|
|
|
// Set the current block counter to being empty.
|
|
|
|
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-22 21:52:13 +08:00
|
|
|
if (!InitState)
|
|
|
|
// Generate the root.
|
|
|
|
GenerateNode(StartLoc, getInitialState(L), 0);
|
|
|
|
else
|
|
|
|
GenerateNode(StartLoc, InitState, 0);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-09-30 07:48:13 +08:00
|
|
|
// Check if we have a steps limit
|
|
|
|
bool UnlimitedSteps = Steps == 0;
|
|
|
|
|
|
|
|
while (WList->hasWork()) {
|
|
|
|
if (!UnlimitedSteps) {
|
|
|
|
if (Steps == 0)
|
|
|
|
break;
|
|
|
|
--Steps;
|
|
|
|
}
|
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
const GRWorkListUnit& WU = WList->Dequeue();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 02:08:17 +08:00
|
|
|
// Set the current block counter.
|
|
|
|
WList->setBlockCounter(WU.getBlockCounter());
|
|
|
|
|
|
|
|
// Retrieve the node.
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode* Node = WU.getNode();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
// Dispatch on the location type.
|
|
|
|
switch (Node->getLocation().getKind()) {
|
2008-12-17 06:13:33 +08:00
|
|
|
case ProgramPoint::BlockEdgeKind:
|
2008-01-15 07:24:37 +08:00
|
|
|
HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
case ProgramPoint::BlockEntranceKind:
|
|
|
|
HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
case ProgramPoint::BlockExitKind:
|
2008-01-15 08:24:08 +08:00
|
|
|
assert (false && "BlockExit location never occur in forward analysis.");
|
2008-01-15 07:24:37 +08:00
|
|
|
break;
|
2008-12-17 06:13:33 +08:00
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
case ProgramPoint::CallEnterKind:
|
|
|
|
HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
|
|
|
|
WU.getIndex(), Node);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ProgramPoint::CallExitKind:
|
|
|
|
HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
|
|
|
|
break;
|
|
|
|
|
2008-12-17 06:13:33 +08:00
|
|
|
default:
|
2010-11-16 15:52:17 +08:00
|
|
|
assert(isa<PostStmt>(Node->getLocation()) ||
|
|
|
|
isa<PostInitializer>(Node->getLocation()));
|
|
|
|
HandlePostStmt(WU.getBlock(), WU.getIndex(), Node);
|
2009-09-09 23:08:12 +08:00
|
|
|
break;
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-11 08:03:02 +08:00
|
|
|
SubEngine.ProcessEndWorklist(hasWorkRemaining());
|
2008-01-15 07:24:37 +08:00
|
|
|
return WList->hasWork();
|
|
|
|
}
|
|
|
|
|
2010-07-22 21:52:13 +08:00
|
|
|
void GRCoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
|
|
|
|
unsigned Steps,
|
|
|
|
const GRState *InitState,
|
|
|
|
ExplodedNodeSet &Dst) {
|
|
|
|
ExecuteWorkList(L, Steps, InitState);
|
|
|
|
for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
|
|
|
|
E = G->EndNodes.end(); I != E; ++I) {
|
|
|
|
Dst.Add(*I);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
|
|
|
|
unsigned Index, ExplodedNode *Pred) {
|
2010-07-19 09:31:21 +08:00
|
|
|
GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(),
|
|
|
|
L.getCalleeContext(), Block, Index);
|
2010-02-26 03:01:53 +08:00
|
|
|
ProcessCallEnter(Builder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
|
|
|
|
GRCallExitNodeBuilder Builder(*this, Pred);
|
|
|
|
ProcessCallExit(Builder);
|
|
|
|
}
|
2009-08-06 18:00:15 +08:00
|
|
|
|
|
|
|
void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const CFGBlock* Blk = L.getDst();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Check if we are entering the EXIT block.
|
2009-12-23 16:54:57 +08:00
|
|
|
if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-23 16:54:57 +08:00
|
|
|
assert (L.getLocationContext()->getCFG()->getExit().size() == 0
|
2008-01-29 08:33:40 +08:00
|
|
|
&& "EXIT block cannot contain Stmts.");
|
2008-01-15 07:24:37 +08:00
|
|
|
|
2008-04-12 06:03:04 +08:00
|
|
|
// Process the final state transition.
|
2009-08-06 20:48:26 +08:00
|
|
|
GREndPathNodeBuilder Builder(Blk, Pred, this);
|
2008-04-12 06:03:04 +08:00
|
|
|
ProcessEndPath(Builder);
|
2008-01-15 07:24:37 +08:00
|
|
|
|
|
|
|
// This path is done. Don't enqueue any more nodes.
|
|
|
|
return;
|
|
|
|
}
|
2008-03-01 04:27:50 +08:00
|
|
|
|
|
|
|
// FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-23 13:05:02 +08:00
|
|
|
if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter()))
|
2010-06-30 05:58:54 +08:00
|
|
|
GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()),
|
|
|
|
Pred->State, Pred);
|
2010-08-11 08:03:02 +08:00
|
|
|
else {
|
|
|
|
blocksAborted.push_back(std::make_pair(L, Pred));
|
|
|
|
}
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2009-08-06 18:00:15 +08:00
|
|
|
void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 02:08:17 +08:00
|
|
|
// Increment the block counter.
|
|
|
|
GRBlockCounter Counter = WList->getBlockCounter();
|
2010-03-23 13:05:02 +08:00
|
|
|
Counter = BCounterFactory.IncrementCount(Counter,
|
|
|
|
Pred->getLocationContext()->getCurrentStackFrame(),
|
|
|
|
L.getBlock()->getBlockID());
|
2008-02-13 02:08:17 +08:00
|
|
|
WList->setBlockCounter(Counter);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Process the entrance of the block.
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
if (CFGElement E = L.getFirstElement()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
|
2009-08-06 20:48:26 +08:00
|
|
|
SubEngine.getStateManager());
|
2010-11-15 16:48:43 +08:00
|
|
|
ProcessElement(E, Builder);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
else
|
2008-01-15 08:24:08 +08:00
|
|
|
HandleBlockExit(L.getBlock(), Pred);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRCoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const Stmt* Term = B->getTerminator()) {
|
2008-01-30 06:56:11 +08:00
|
|
|
switch (Term->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
assert(false && "Analysis for this terminator not implemented.");
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 05:51:20 +08:00
|
|
|
case Stmt::BinaryOperatorClass: // '&&' and '||'
|
|
|
|
HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-05 08:26:40 +08:00
|
|
|
case Stmt::ConditionalOperatorClass:
|
|
|
|
HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred);
|
2008-02-13 05:51:20 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 05:51:20 +08:00
|
|
|
// FIXME: Use constant-folding in CFG construction to simplify this
|
|
|
|
// case.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-05 08:26:40 +08:00
|
|
|
case Stmt::ChooseExprClass:
|
|
|
|
HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
|
2008-02-13 05:51:20 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 05:51:20 +08:00
|
|
|
case Stmt::DoStmtClass:
|
|
|
|
HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-30 06:56:11 +08:00
|
|
|
case Stmt::ForStmtClass:
|
|
|
|
HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
|
2008-02-13 05:51:20 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 00:56:51 +08:00
|
|
|
case Stmt::ContinueStmtClass:
|
|
|
|
case Stmt::BreakStmtClass:
|
2009-09-09 23:08:12 +08:00
|
|
|
case Stmt::GotoStmtClass:
|
2008-01-30 06:56:11 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 05:51:20 +08:00
|
|
|
case Stmt::IfStmtClass:
|
|
|
|
HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
case Stmt::IndirectGotoStmtClass: {
|
|
|
|
// Only 1 successor: the indirect goto dispatch block.
|
|
|
|
assert (B->succ_size() == 1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
GRIndirectGotoNodeBuilder
|
2008-02-13 08:24:44 +08:00
|
|
|
builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
|
|
|
|
*(B->succ_begin()), this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
ProcessIndirectGoto(builder);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-13 03:24:17 +08:00
|
|
|
case Stmt::ObjCForCollectionStmtClass: {
|
|
|
|
// In the case of ObjCForCollectionStmt, it appears twice in a CFG:
|
|
|
|
//
|
|
|
|
// (1) inside a basic block, which represents the binding of the
|
|
|
|
// 'element' variable to a value.
|
|
|
|
// (2) in a terminator, which represents the branch.
|
|
|
|
//
|
|
|
|
// For (1), subengines will bind a value (i.e., 0 or 1) indicating
|
|
|
|
// whether or not collection contains any more elements. We cannot
|
|
|
|
// just test to see if the element is nil because a container can
|
|
|
|
// contain nil elements.
|
|
|
|
HandleBranch(Term, Term, B, Pred);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
case Stmt::SwitchStmtClass: {
|
2009-08-06 20:48:26 +08:00
|
|
|
GRSwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
|
|
|
|
this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
ProcessSwitch(builder);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-30 06:56:11 +08:00
|
|
|
case Stmt::WhileStmtClass:
|
|
|
|
HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
|
2008-02-13 05:51:20 +08:00
|
|
|
return;
|
2008-01-30 06:56:11 +08:00
|
|
|
}
|
|
|
|
}
|
2008-02-13 05:51:20 +08:00
|
|
|
|
|
|
|
assert (B->succ_size() == 1 &&
|
|
|
|
"Blocks with no terminator should have at most 1 successor.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
GenerateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
|
2009-08-15 11:17:38 +08:00
|
|
|
Pred->State, Pred);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRCoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term,
|
|
|
|
const CFGBlock * B, ExplodedNode* Pred) {
|
2008-01-30 06:56:11 +08:00
|
|
|
assert (B->succ_size() == 2);
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
GRBranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
|
|
|
|
Pred, this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-30 06:56:11 +08:00
|
|
|
ProcessBranch(Cond, Term, Builder);
|
|
|
|
}
|
|
|
|
|
2010-11-16 15:52:17 +08:00
|
|
|
void GRCoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx,
|
|
|
|
ExplodedNode* Pred) {
|
2008-01-15 07:24:37 +08:00
|
|
|
assert (!B->empty());
|
|
|
|
|
2008-01-15 08:24:08 +08:00
|
|
|
if (StmtIdx == B->size())
|
|
|
|
HandleBlockExit(B, Pred);
|
2008-01-15 07:24:37 +08:00
|
|
|
else {
|
2009-09-09 23:08:12 +08:00
|
|
|
GRStmtNodeBuilder Builder(B, StmtIdx, Pred, this,
|
2009-08-06 20:48:26 +08:00
|
|
|
SubEngine.getStateManager());
|
2010-11-15 16:48:43 +08:00
|
|
|
ProcessElement((*B)[StmtIdx], Builder);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// GenerateNode - Utility method to generate nodes, hook up successors,
|
|
|
|
/// and add nodes to the worklist.
|
2009-09-09 23:08:12 +08:00
|
|
|
void GRCoreEngine::GenerateNode(const ProgramPoint& Loc,
|
2009-08-06 18:00:15 +08:00
|
|
|
const GRState* State, ExplodedNode* Pred) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
bool IsNew;
|
2009-08-06 14:28:40 +08:00
|
|
|
ExplodedNode* Node = G->getNode(Loc, State, &IsNew);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (Pred)
|
2009-10-07 08:42:52 +08:00
|
|
|
Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor.
|
2008-01-15 07:24:37 +08:00
|
|
|
else {
|
|
|
|
assert (IsNew);
|
|
|
|
G->addRoot(Node); // 'Node' has no predecessor. Make it a root.
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
// Only add 'Node' to the worklist if it was freshly generated.
|
2008-02-13 02:08:17 +08:00
|
|
|
if (IsNew) WList->Enqueue(Node);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
GRStmtNodeBuilder::GRStmtNodeBuilder(const CFGBlock* b, unsigned idx,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* N, GRCoreEngine* e,
|
|
|
|
GRStateManager &mgr)
|
2010-10-21 07:48:34 +08:00
|
|
|
: Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr),
|
2009-08-06 20:48:26 +08:00
|
|
|
PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
|
|
|
|
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
|
2008-01-15 07:24:37 +08:00
|
|
|
Deferred.insert(N);
|
2010-02-26 10:38:09 +08:00
|
|
|
CleanedState = Pred->getState();
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
GRStmtNodeBuilder::~GRStmtNodeBuilder() {
|
2008-01-15 07:24:37 +08:00
|
|
|
for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
|
2008-01-31 07:03:39 +08:00
|
|
|
if (!(*I)->isSink())
|
2008-01-15 07:24:37 +08:00
|
|
|
GenerateAutoTransition(*I);
|
|
|
|
}
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
|
2008-01-31 07:03:39 +08:00
|
|
|
assert (!N->isSink());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
// Check if this node entered a callee.
|
|
|
|
if (isa<CallEnter>(N->getLocation())) {
|
|
|
|
// Still use the index of the CallExpr. It's needed to create the callee
|
|
|
|
// StackFrameContext.
|
2010-07-20 14:22:24 +08:00
|
|
|
Eng.WList->Enqueue(N, &B, Idx);
|
2010-02-26 03:01:53 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-16 15:52:17 +08:00
|
|
|
// Do not create extra nodes. Move to the next CFG element.
|
|
|
|
if (isa<PostInitializer>(N->getLocation())) {
|
|
|
|
Eng.WList->Enqueue(N, &B, Idx+1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-15 11:17:38 +08:00
|
|
|
PostStmt Loc(getStmt(), N->getLocationContext());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
if (Loc == N->getLocation()) {
|
|
|
|
// Note: 'N' should be a fresh node because otherwise it shouldn't be
|
|
|
|
// a member of Deferred.
|
2010-07-20 14:22:24 +08:00
|
|
|
Eng.WList->Enqueue(N, &B, Idx+1);
|
2008-01-15 07:24:37 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
bool IsNew;
|
2009-08-06 14:28:40 +08:00
|
|
|
ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew);
|
2009-10-07 08:42:52 +08:00
|
|
|
Succ->addPredecessor(N, *Eng.G);
|
2008-01-15 07:24:37 +08:00
|
|
|
|
|
|
|
if (IsNew)
|
2010-07-20 14:22:24 +08:00
|
|
|
Eng.WList->Enqueue(Succ, &B, Idx+1);
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 10:41:28 +08:00
|
|
|
ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
|
2010-04-14 14:35:09 +08:00
|
|
|
ExplodedNode* Pred, const GRState* St,
|
|
|
|
ProgramPoint::Kind K) {
|
|
|
|
|
|
|
|
ExplodedNode* N = generateNode(S, St, Pred, K);
|
|
|
|
|
|
|
|
if (N) {
|
|
|
|
if (BuildSinks)
|
|
|
|
N->markAsSink();
|
2010-10-21 07:48:34 +08:00
|
|
|
else
|
2010-04-14 14:35:09 +08:00
|
|
|
Dst.Add(N);
|
|
|
|
}
|
|
|
|
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
|
|
|
const LocationContext *LC, const void *tag){
|
2008-06-18 13:34:07 +08:00
|
|
|
switch (K) {
|
|
|
|
default:
|
2009-11-11 11:26:34 +08:00
|
|
|
assert(false && "Unhandled ProgramPoint kind");
|
|
|
|
case ProgramPoint::PreStmtKind:
|
|
|
|
return PreStmt(S, LC, tag);
|
2008-06-18 13:34:07 +08:00
|
|
|
case ProgramPoint::PostStmtKind:
|
2009-11-11 11:26:34 +08:00
|
|
|
return PostStmt(S, LC, tag);
|
|
|
|
case ProgramPoint::PreLoadKind:
|
|
|
|
return PreLoad(S, LC, tag);
|
2008-06-18 13:34:07 +08:00
|
|
|
case ProgramPoint::PostLoadKind:
|
2009-11-11 11:26:34 +08:00
|
|
|
return PostLoad(S, LC, tag);
|
|
|
|
case ProgramPoint::PreStoreKind:
|
|
|
|
return PreStore(S, LC, tag);
|
2008-10-18 04:49:23 +08:00
|
|
|
case ProgramPoint::PostStoreKind:
|
2009-11-11 11:26:34 +08:00
|
|
|
return PostStore(S, LC, tag);
|
2009-05-08 02:27:16 +08:00
|
|
|
case ProgramPoint::PostLValueKind:
|
2009-11-11 11:26:34 +08:00
|
|
|
return PostLValue(S, LC, tag);
|
2008-06-18 13:34:07 +08:00
|
|
|
case ProgramPoint::PostPurgeDeadSymbolsKind:
|
2009-11-11 11:26:34 +08:00
|
|
|
return PostPurgeDeadSymbols(S, LC, tag);
|
2008-06-18 13:34:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-11-11 11:26:34 +08:00
|
|
|
GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode* Pred,
|
2009-04-11 08:11:10 +08:00
|
|
|
ProgramPoint::Kind K,
|
|
|
|
const void *tag) {
|
2009-11-11 11:26:34 +08:00
|
|
|
|
2009-12-23 16:54:57 +08:00
|
|
|
const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
|
2009-11-11 11:26:34 +08:00
|
|
|
return generateNodeInternal(L, state, Pred);
|
2009-02-20 07:45:28 +08:00
|
|
|
}
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-08-06 20:48:26 +08:00
|
|
|
GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
|
2009-08-06 14:28:40 +08:00
|
|
|
const GRState* State,
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode* Pred) {
|
2008-01-15 07:24:37 +08:00
|
|
|
bool IsNew;
|
2009-08-06 14:28:40 +08:00
|
|
|
ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew);
|
2009-10-07 08:42:52 +08:00
|
|
|
N->addPredecessor(Pred, *Eng.G);
|
2008-01-15 07:24:37 +08:00
|
|
|
Deferred.erase(Pred);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-15 07:24:37 +08:00
|
|
|
if (IsNew) {
|
|
|
|
Deferred.insert(N);
|
|
|
|
return N;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return NULL;
|
2008-01-15 07:24:37 +08:00
|
|
|
}
|
2008-01-30 06:56:11 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* GRBranchNodeBuilder::generateNode(const GRState* State,
|
|
|
|
bool branch) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-21 02:44:36 +08:00
|
|
|
// If the branch has been marked infeasible we should not generate a node.
|
|
|
|
if (!isFeasible(branch))
|
|
|
|
return NULL;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-30 06:56:11 +08:00
|
|
|
bool IsNew;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode* Succ =
|
2009-08-15 11:17:38 +08:00
|
|
|
Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
|
|
|
|
State, &IsNew);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-07 08:42:52 +08:00
|
|
|
Succ->addPredecessor(Pred, *Eng.G);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-21 02:44:36 +08:00
|
|
|
if (branch)
|
|
|
|
GeneratedTrue = true;
|
|
|
|
else
|
2009-09-09 23:08:12 +08:00
|
|
|
GeneratedFalse = true;
|
|
|
|
|
2008-01-31 07:03:39 +08:00
|
|
|
if (IsNew) {
|
2008-01-31 07:24:39 +08:00
|
|
|
Deferred.push_back(Succ);
|
2008-01-31 07:03:39 +08:00
|
|
|
return Succ;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-31 07:03:39 +08:00
|
|
|
return NULL;
|
2008-01-30 06:56:11 +08:00
|
|
|
}
|
2008-01-30 07:32:35 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
GRBranchNodeBuilder::~GRBranchNodeBuilder() {
|
|
|
|
if (!GeneratedTrue) generateNode(Pred->State, true);
|
|
|
|
if (!GeneratedFalse) generateNode(Pred->State, false);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-31 07:24:39 +08:00
|
|
|
for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
|
2008-02-13 02:08:17 +08:00
|
|
|
if (!(*I)->isSink()) Eng.WList->Enqueue(*I);
|
2008-01-30 07:32:35 +08:00
|
|
|
}
|
2008-02-13 08:24:44 +08:00
|
|
|
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-08-06 20:48:26 +08:00
|
|
|
GRIndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
|
|
|
|
bool isSink) {
|
2008-02-13 08:24:44 +08:00
|
|
|
bool IsNew;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
|
2009-08-15 11:17:38 +08:00
|
|
|
Pred->getLocationContext()), St, &IsNew);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-07 08:42:52 +08:00
|
|
|
Succ->addPredecessor(Pred, *Eng.G);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
if (IsNew) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
if (isSink)
|
|
|
|
Succ->markAsSink();
|
|
|
|
else
|
|
|
|
Eng.WList->Enqueue(Succ);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
return Succ;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-02-14 07:08:21 +08:00
|
|
|
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-08-06 20:48:26 +08:00
|
|
|
GRSwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){
|
2008-02-14 07:08:21 +08:00
|
|
|
|
|
|
|
bool IsNew;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-15 11:17:38 +08:00
|
|
|
ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
|
|
|
|
Pred->getLocationContext()), St, &IsNew);
|
2009-10-07 08:42:52 +08:00
|
|
|
Succ->addPredecessor(Pred, *Eng.G);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
if (IsNew) {
|
|
|
|
Eng.WList->Enqueue(Succ);
|
|
|
|
return Succ;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-08-06 20:48:26 +08:00
|
|
|
GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// Get the block for the default case.
|
|
|
|
assert (Src->succ_rbegin() != Src->succ_rend());
|
|
|
|
CFGBlock* DefaultBlock = *Src->succ_rbegin();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
bool IsNew;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-15 11:17:38 +08:00
|
|
|
ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
|
|
|
|
Pred->getLocationContext()), St, &IsNew);
|
2009-10-07 08:42:52 +08:00
|
|
|
Succ->addPredecessor(Pred, *Eng.G);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
if (IsNew) {
|
|
|
|
if (isSink)
|
|
|
|
Succ->markAsSink();
|
|
|
|
else
|
|
|
|
Eng.WList->Enqueue(Succ);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
return Succ;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-04-12 06:03:04 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
GREndPathNodeBuilder::~GREndPathNodeBuilder() {
|
2008-04-12 06:03:04 +08:00
|
|
|
// Auto-generate an EOP node if one has not been generated.
|
2010-02-26 03:01:53 +08:00
|
|
|
if (!HasGeneratedNode) {
|
|
|
|
// If we are in an inlined call, generate CallExit node.
|
|
|
|
if (Pred->getLocationContext()->getParent())
|
|
|
|
GenerateCallExitNode(Pred->State);
|
|
|
|
else
|
|
|
|
generateNode(Pred->State);
|
|
|
|
}
|
2008-04-12 06:03:04 +08:00
|
|
|
}
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode*
|
2009-08-06 20:48:26 +08:00
|
|
|
GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
|
|
|
|
ExplodedNode* P) {
|
2009-09-09 23:08:12 +08:00
|
|
|
HasGeneratedNode = true;
|
2008-04-12 06:03:04 +08:00
|
|
|
bool IsNew;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
|
2009-08-15 11:17:38 +08:00
|
|
|
Pred->getLocationContext(), tag), State, &IsNew);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-07 08:42:52 +08:00
|
|
|
Node->addPredecessor(P ? P : Pred, *Eng.G);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-12 06:03:04 +08:00
|
|
|
if (IsNew) {
|
|
|
|
Eng.G->addEndOfPath(Node);
|
2008-04-19 00:30:14 +08:00
|
|
|
return Node;
|
2008-04-12 06:03:04 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-19 00:30:14 +08:00
|
|
|
return NULL;
|
2008-04-12 06:03:04 +08:00
|
|
|
}
|
2010-02-26 03:01:53 +08:00
|
|
|
|
|
|
|
void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) {
|
|
|
|
HasGeneratedNode = true;
|
|
|
|
// Create a CallExit node and enqueue it.
|
|
|
|
const StackFrameContext *LocCtx
|
|
|
|
= cast<StackFrameContext>(Pred->getLocationContext());
|
|
|
|
const Stmt *CE = LocCtx->getCallSite();
|
|
|
|
|
|
|
|
// Use the the callee location context.
|
|
|
|
CallExit Loc(CE, LocCtx);
|
|
|
|
|
|
|
|
bool isNew;
|
|
|
|
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
|
|
|
|
Node->addPredecessor(Pred, *Eng.G);
|
|
|
|
|
|
|
|
if (isNew)
|
|
|
|
Eng.WList->Enqueue(Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
|
|
|
|
const LocationContext *LocCtx) {
|
2010-07-19 09:31:21 +08:00
|
|
|
// Check if the callee is in the same translation unit.
|
|
|
|
if (CalleeCtx->getTranslationUnit() !=
|
|
|
|
Pred->getLocationContext()->getTranslationUnit()) {
|
2010-07-22 21:52:13 +08:00
|
|
|
// Create a new engine. We must be careful that the new engine should not
|
|
|
|
// reference data structures owned by the old engine.
|
|
|
|
|
|
|
|
AnalysisManager &OldMgr = Eng.SubEngine.getAnalysisManager();
|
|
|
|
|
|
|
|
// Get the callee's translation unit.
|
|
|
|
idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
|
|
|
|
|
|
|
|
// Create a new AnalysisManager with components of the callee's
|
|
|
|
// TranslationUnit.
|
2010-08-19 07:57:06 +08:00
|
|
|
// The Diagnostic is actually shared when we create ASTUnits from AST files.
|
2010-07-22 21:52:13 +08:00
|
|
|
AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(),
|
|
|
|
OldMgr.getLangOptions(),
|
|
|
|
OldMgr.getPathDiagnosticClient(),
|
|
|
|
OldMgr.getStoreManagerCreator(),
|
|
|
|
OldMgr.getConstraintManagerCreator(),
|
|
|
|
OldMgr.getIndexer(),
|
2010-09-15 05:35:27 +08:00
|
|
|
OldMgr.getMaxNodes(), OldMgr.getMaxVisit(),
|
2010-07-22 21:52:13 +08:00
|
|
|
OldMgr.shouldVisualizeGraphviz(),
|
|
|
|
OldMgr.shouldVisualizeUbigraph(),
|
|
|
|
OldMgr.shouldPurgeDead(),
|
|
|
|
OldMgr.shouldEagerlyAssume(),
|
|
|
|
OldMgr.shouldTrimGraph(),
|
2010-08-03 08:09:51 +08:00
|
|
|
OldMgr.shouldInlineCall(),
|
2010-09-30 15:41:24 +08:00
|
|
|
OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
|
|
|
|
OldMgr.getAnalysisContextManager().getAddImplicitDtors(),
|
|
|
|
OldMgr.getAnalysisContextManager().getAddInitializers());
|
2010-07-22 21:52:13 +08:00
|
|
|
llvm::OwningPtr<GRTransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
|
|
|
|
/* GCEnabled */ false,
|
|
|
|
AMgr.getLangOptions()));
|
|
|
|
// Create the new engine.
|
|
|
|
GRExprEngine NewEng(AMgr, TF.take());
|
|
|
|
|
|
|
|
// Create the new LocationContext.
|
|
|
|
AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
|
|
|
|
CalleeCtx->getTranslationUnit());
|
|
|
|
const StackFrameContext *OldLocCtx = cast<StackFrameContext>(LocCtx);
|
|
|
|
const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx,
|
|
|
|
OldLocCtx->getParent(),
|
|
|
|
OldLocCtx->getCallSite(),
|
|
|
|
OldLocCtx->getCallSiteBlock(),
|
|
|
|
OldLocCtx->getIndex());
|
|
|
|
|
|
|
|
// Now create an initial state for the new engine.
|
|
|
|
const GRState *NewState = NewEng.getStateManager().MarshalState(state,
|
|
|
|
NewLocCtx);
|
|
|
|
ExplodedNodeSet ReturnNodes;
|
|
|
|
NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
|
|
|
|
NewState, ReturnNodes);
|
|
|
|
return;
|
2010-07-19 09:31:21 +08:00
|
|
|
}
|
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
// Get the callee entry block.
|
|
|
|
const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry());
|
|
|
|
assert(Entry->empty());
|
|
|
|
assert(Entry->succ_size() == 1);
|
|
|
|
|
|
|
|
// Get the solitary successor.
|
|
|
|
const CFGBlock *SuccB = *(Entry->succ_begin());
|
|
|
|
|
|
|
|
// Construct an edge representing the starting location in the callee.
|
|
|
|
BlockEdge Loc(Entry, SuccB, LocCtx);
|
|
|
|
|
|
|
|
bool isNew;
|
|
|
|
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
|
|
|
|
Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
|
|
|
|
|
|
|
|
if (isNew)
|
|
|
|
Eng.WList->Enqueue(Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GRCallExitNodeBuilder::GenerateNode(const GRState *state) {
|
|
|
|
// Get the callee's location context.
|
|
|
|
const StackFrameContext *LocCtx
|
|
|
|
= cast<StackFrameContext>(Pred->getLocationContext());
|
|
|
|
|
|
|
|
PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
|
|
|
|
bool isNew;
|
|
|
|
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
|
|
|
|
Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
|
|
|
|
if (isNew)
|
2010-07-20 14:22:24 +08:00
|
|
|
Eng.WList->Enqueue(Node, LocCtx->getCallSiteBlock(),
|
2010-02-26 03:01:53 +08:00
|
|
|
LocCtx->getIndex() + 1);
|
|
|
|
}
|