blob: a8c741f7485e272d70e305a642f452232a0fab3c [file] [log] [blame]
//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
//
// 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.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
#define LLVM_CLANG_ANALYSIS_GRENGINE
#include "clang/AST/Expr.h"
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "clang/Analysis/PathSensitive/GRWorkList.h"
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
#include "clang/Analysis/PathSensitive/GRAuditor.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
class GRStmtNodeBuilderImpl;
class GRBranchNodeBuilderImpl;
class GRIndirectGotoNodeBuilderImpl;
class GRSwitchNodeBuilderImpl;
class GREndPathNodeBuilderImpl;
class GRWorkList;
//===----------------------------------------------------------------------===//
/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
/// analysis. It traverses the CFG and generates the ExplodedGraph.
/// Program "states" are treated as opaque void pointers.
/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
/// provides the matching component to the engine that knows the actual types
/// for states. Note that this engine only dispatches to transfer functions
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class GRCoreEngineImpl {
protected:
friend class GRStmtNodeBuilderImpl;
friend class GRBranchNodeBuilderImpl;
friend class GRIndirectGotoNodeBuilderImpl;
friend class GRSwitchNodeBuilderImpl;
friend class GREndPathNodeBuilderImpl;
/// G - The simulation graph. Each node is a (location,state) pair.
llvm::OwningPtr<ExplodedGraphImpl> G;
/// WList - A set of queued nodes that need to be processed by the
/// worklist algorithm. It is up to the implementation of WList to decide
/// the order that nodes are processed.
GRWorkList* WList;
/// BCounterFactory - A factory object for created GRBlockCounter objects.
/// These are used to record for key nodes in the ExplodedGraph the
/// number of times different CFGBlocks have been visited along a path.
GRBlockCounter::Factory BCounterFactory;
void GenerateNode(const ProgramPoint& Loc, const void* State,
ExplodedNode* Pred);
/// getInitialState - Gets the void* representing the initial 'state'
/// of the analysis. This is simply a wrapper (implemented
/// in GRCoreEngine) that performs type erasure on the initial
/// state returned by the checker object.
virtual const void* getInitialState() = 0;
void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred);
void HandlePostStmt(const PostStmt& S, CFGBlock* B,
unsigned StmtIdx, ExplodedNode *Pred);
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
ExplodedNode* Pred);
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
GRBlockCounter BC) = 0;
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
GRBranchNodeBuilderImpl& Builder) = 0;
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
private:
GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
protected:
GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
: G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(unsigned Steps);
virtual ~GRCoreEngineImpl();
CFG& getCFG() { return G->getCFG(); }
};
class GRStmtNodeBuilderImpl {
GRCoreEngineImpl& Eng;
CFGBlock& B;
const unsigned Idx;
ExplodedNode* Pred;
ExplodedNode* LastNode;
typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
DeferredTy Deferred;
void GenerateAutoTransition(ExplodedNode* N);
public:
GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
ExplodedNode* N, GRCoreEngineImpl* e);
~GRStmtNodeBuilderImpl();
ExplodedNode* getBasePredecessor() const { return Pred; }
ExplodedNode* getLastNode() const {
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
}
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
return getBlockCounter().getNumVisited(B.getBlockID());
}
ExplodedNode*
generateNodeImpl(const ProgramPoint &PP, const void* State,
ExplodedNode* Pred);
ExplodedNode*
generateNodeImpl(const Stmt* S, const void* State, ExplodedNode* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
ExplodedNode*
generateNodeImpl(const Stmt* S, const void* State,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0) {
ExplodedNode* N = getLastNode();
assert (N && "Predecessor of new node is infeasible.");
return generateNodeImpl(S, State, N, K, tag);
}
ExplodedNode*
generateNodeImpl(const Stmt* S, const void* State, const void *tag = 0) {
ExplodedNode* N = getLastNode();
assert (N && "Predecessor of new node is infeasible.");
return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
}
/// getStmt - Return the current block-level expression associated with
/// this builder.
Stmt* getStmt() const { return B[Idx]; }
/// getBlock - Return the CFGBlock associated with the block-level expression
/// of this builder.
CFGBlock* getBlock() const { return &B; }
};
template<typename STATE>
class GRStmtNodeBuilder {
public:
typedef STATE StateTy;
typedef typename StateTy::ManagerTy StateManagerTy;
typedef ExplodedNode NodeTy;
private:
GRStmtNodeBuilderImpl& NB;
StateManagerTy& Mgr;
const StateTy* CleanedState;
GRAuditor<StateTy>* Auditor;
public:
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
BuildSinks(false), HasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
CleanedState = getLastNode()->getState();
}
void setAuditor(GRAuditor<StateTy>* A) {
Auditor = A;
}
NodeTy* getLastNode() const {
return static_cast<NodeTy*>(NB.getLastNode());
}
NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
HasGeneratedNode = true;
return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
}
NodeTy* generateNode(const Stmt* S, const StateTy* St, NodeTy* Pred,
ProgramPoint::Kind K) {
HasGeneratedNode = true;
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
}
NodeTy* generateNode(const Stmt* S, const StateTy* St, NodeTy* Pred) {
return generateNode(S, St, Pred, PointKind);
}
NodeTy* generateNode(const Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
HasGeneratedNode = true;
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
}
NodeTy* generateNode(const Stmt* S, const StateTy* St) {
return generateNode(S, St, PointKind);
}
GRBlockCounter getBlockCounter() const {
return NB.getBlockCounter();
}
unsigned getCurrentBlockCount() const {
return NB.getCurrentBlockCount();
}
const StateTy* GetState(NodeTy* Pred) const {
if ((ExplodedNode*) Pred == NB.getBasePredecessor())
return CleanedState;
else
return Pred->getState();
}
void SetCleanedState(const StateTy* St) {
CleanedState = St;
}
NodeTy* MakeNode(ExplodedNodeSet& Dst, Stmt* S,
NodeTy* Pred, const StateTy* St) {
return MakeNode(Dst, S, Pred, St, PointKind);
}
NodeTy* MakeNode(ExplodedNodeSet& Dst, Stmt* S,
NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
const StateTy* PredState = GetState(Pred);
// If the state hasn't changed, don't generate a new node.
if (!BuildSinks && St == PredState && Auditor == 0) {
Dst.Add(Pred);
return NULL;
}
NodeTy* N = generateNode(S, St, Pred, K);
if (N) {
if (BuildSinks)
N->markAsSink();
else {
if (Auditor && Auditor->Audit(N, Mgr))
N->markAsSink();
Dst.Add(N);
}
}
return N;
}
NodeTy* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S,
NodeTy* Pred, const StateTy* St) {
bool Tmp = BuildSinks;
BuildSinks = true;
NodeTy* N = MakeNode(Dst, S, Pred, St);
BuildSinks = Tmp;
return N;
}
bool PurgingDeadSymbols;
bool BuildSinks;
bool HasGeneratedNode;
ProgramPoint::Kind PointKind;
const void *Tag;
};
class GRBranchNodeBuilderImpl {
GRCoreEngineImpl& Eng;
CFGBlock* Src;
CFGBlock* DstT;
CFGBlock* DstF;
ExplodedNode* Pred;
typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
DeferredTy Deferred;
bool GeneratedTrue;
bool GeneratedFalse;
bool InFeasibleTrue;
bool InFeasibleFalse;
public:
GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
ExplodedNode* pred, GRCoreEngineImpl* e)
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
GeneratedTrue(false), GeneratedFalse(false),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
~GRBranchNodeBuilderImpl();
ExplodedNode* getPredecessor() const { return Pred; }
const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
ExplodedNode* generateNodeImpl(const void* State, bool branch);
CFGBlock* getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}
void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = GeneratedTrue = true;
else
InFeasibleFalse = GeneratedFalse = true;
}
bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
};
template<typename STATE>
class GRBranchNodeBuilder {
typedef STATE StateTy;
typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRBranchNodeBuilderImpl& NB;
public:
GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
const GraphTy& getGraph() const {
return static_cast<const GraphTy&>(NB.getGraph());
}
NodeTy* getPredecessor() const {
return static_cast<NodeTy*>(NB.getPredecessor());
}
const StateTy* getState() const {
return getPredecessor()->getState();
}
NodeTy* generateNode(const StateTy* St, bool branch) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
}
GRBlockCounter getBlockCounter() const {
return NB.getBlockCounter();
}
CFGBlock* getTargetBlock(bool branch) const {
return NB.getTargetBlock(branch);
}
void markInfeasible(bool branch) {
NB.markInfeasible(branch);
}
bool isFeasible(bool branch) {
return NB.isFeasible(branch);
}
};
class GRIndirectGotoNodeBuilderImpl {
GRCoreEngineImpl& Eng;
CFGBlock* Src;
CFGBlock& DispatchBlock;
Expr* E;
ExplodedNode* Pred;
public:
GRIndirectGotoNodeBuilderImpl(ExplodedNode* pred, CFGBlock* src,
Expr* e, CFGBlock* dispatch,
GRCoreEngineImpl* eng)
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
class Iterator {
CFGBlock::succ_iterator I;
friend class GRIndirectGotoNodeBuilderImpl;
Iterator(CFGBlock::succ_iterator i) : I(i) {}
public:
Iterator& operator++() { ++I; return *this; }
bool operator!=(const Iterator& X) const { return I != X.I; }
LabelStmt* getLabel() const {
return llvm::cast<LabelStmt>((*I)->getLabel());
}
CFGBlock* getBlock() const {
return *I;
}
};
Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
Iterator end() { return Iterator(DispatchBlock.succ_end()); }
ExplodedNode* generateNodeImpl(const Iterator& I, const void* State,
bool isSink);
Expr* getTarget() const { return E; }
const void* getState() const { return Pred->State; }
};
template<typename STATE>
class GRIndirectGotoNodeBuilder {
typedef STATE StateTy;
typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRIndirectGotoNodeBuilderImpl& NB;
public:
GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
iterator begin() { return NB.begin(); }
iterator end() { return NB.end(); }
Expr* getTarget() const { return NB.getTarget(); }
NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
}
const StateTy* getState() const {
return static_cast<const StateTy*>(NB.getState());
}
};
class GRSwitchNodeBuilderImpl {
GRCoreEngineImpl& Eng;
CFGBlock* Src;
Expr* Condition;
ExplodedNode* Pred;
public:
GRSwitchNodeBuilderImpl(ExplodedNode* pred, CFGBlock* src,
Expr* condition, GRCoreEngineImpl* eng)
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
class Iterator {
CFGBlock::succ_reverse_iterator I;
friend class GRSwitchNodeBuilderImpl;
Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
public:
Iterator& operator++() { ++I; return *this; }
bool operator!=(const Iterator& X) const { return I != X.I; }
CaseStmt* getCase() const {
return llvm::cast<CaseStmt>((*I)->getLabel());
}
CFGBlock* getBlock() const {
return *I;
}
};
Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
Iterator end() { return Iterator(Src->succ_rend()); }
ExplodedNode* generateCaseStmtNodeImpl(const Iterator& I,
const void* State);
ExplodedNode* generateDefaultCaseNodeImpl(const void* State,
bool isSink);
Expr* getCondition() const { return Condition; }
const void* getState() const { return Pred->State; }
};
template<typename STATE>
class GRSwitchNodeBuilder {
typedef STATE StateTy;
typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRSwitchNodeBuilderImpl& NB;
public:
GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
typedef GRSwitchNodeBuilderImpl::Iterator iterator;
iterator begin() { return NB.begin(); }
iterator end() { return NB.end(); }
Expr* getCondition() const { return NB.getCondition(); }
NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
}
NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
}
const StateTy* getState() const {
return static_cast<const StateTy*>(NB.getState());
}
};
class GREndPathNodeBuilderImpl {
GRCoreEngineImpl& Eng;
CFGBlock& B;
ExplodedNode* Pred;
bool HasGeneratedNode;
public:
GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNode* N,
GRCoreEngineImpl* e)
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
~GREndPathNodeBuilderImpl();
ExplodedNode* getPredecessor() const { return Pred; }
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
return getBlockCounter().getNumVisited(B.getBlockID());
}
ExplodedNode* generateNodeImpl(const void* State,
const void *tag = 0,
ExplodedNode *P = 0);
CFGBlock* getBlock() const { return &B; }
};
template<typename STATE>
class GREndPathNodeBuilder {
typedef STATE StateTy;
typedef ExplodedNode NodeTy;
GREndPathNodeBuilderImpl& NB;
public:
GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
NodeTy* getPredecessor() const {
return static_cast<NodeTy*>(NB.getPredecessor());
}
GRBlockCounter getBlockCounter() const {
return NB.getBlockCounter();
}
unsigned getCurrentBlockCount() const {
return NB.getCurrentBlockCount();
}
const StateTy* getState() const {
return getPredecessor()->getState();
}
NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
}
NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
}
};
template<typename SUBENGINE>
class GRCoreEngine : public GRCoreEngineImpl {
public:
typedef SUBENGINE SubEngineTy;
typedef typename SubEngineTy::StateTy StateTy;
typedef typename StateTy::ManagerTy StateManagerTy;
typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
protected:
SubEngineTy& SubEngine;
virtual const void* getInitialState() {
return SubEngine.getInitialState();
}
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
SubEngine.ProcessEndPath(Builder);
}
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
SubEngine.ProcessStmt(S, Builder);
}
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
GRBlockCounter BC) {
return SubEngine.ProcessBlockEntrance(Blk,
static_cast<const StateTy*>(State),
BC);
}
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
GRBranchNodeBuilderImpl& BuilderImpl) {
GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
SubEngine.ProcessBranch(Condition, Terminator, Builder);
}
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
SubEngine.ProcessIndirectGoto(Builder);
}
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
SubEngine.ProcessSwitch(Builder);
}
public:
/// Construct a GRCoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph.
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
GRWorkList::MakeBFS()),
SubEngine(subengine) {}
/// Construct a GRCoreEngine object to analyze the provided CFG and to
/// use the provided worklist object to execute the worklist algorithm.
/// The GRCoreEngine object assumes ownership of 'wlist'.
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
SubEngineTy& subengine)
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
SubEngine(subengine) {}
virtual ~GRCoreEngine() {}
/// getGraph - Returns the exploded graph.
GraphTy& getGraph() {
return *static_cast<GraphTy*>(G.get());
}
/// takeGraph - Returns the exploded graph. Ownership of the graph is
/// transfered to the caller.
GraphTy* takeGraph() {
return static_cast<GraphTy*>(G.take());
}
};
} // end clang namespace
#endif