[cfe-commits] r47100 - in /cfe/trunk: Analysis/GRCoreEngine.cpp Analysis/GRExprEngine.cpp include/clang/Analysis/PathSensitive/ExplodedGraph.h include/clang/Analysis/PathSensitive/GRCoreEngine.h
Ted Kremenek
kremenek at apple.com
Wed Feb 13 15:08:21 PST 2008
Author: kremenek
Date: Wed Feb 13 17:08:21 2008
New Revision: 47100
URL: http://llvm.org/viewvc/llvm-project?rev=47100&view=rev
Log:
Added support to GRCoreEngine/GRExprEngine for processing control-flow
from switch...case...default statements.
Modified:
cfe/trunk/Analysis/GRCoreEngine.cpp
cfe/trunk/Analysis/GRExprEngine.cpp
cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h
cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
Modified: cfe/trunk/Analysis/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRCoreEngine.cpp?rev=47100&r1=47099&r2=47100&view=diff
==============================================================================
--- cfe/trunk/Analysis/GRCoreEngine.cpp (original)
+++ cfe/trunk/Analysis/GRCoreEngine.cpp Wed Feb 13 17:08:21 2008
@@ -213,6 +213,15 @@
return;
}
+ case Stmt::SwitchStmtClass: {
+ GRSwitchNodeBuilderImpl builder(Pred, B,
+ cast<SwitchStmt>(Term)->getCond(),
+ this);
+
+ ProcessSwitch(builder);
+ return;
+ }
+
case Stmt::WhileStmtClass:
HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
return;
@@ -386,3 +395,49 @@
return NULL;
}
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, void* St) {
+
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src,
+ I.getBlock()),
+ St, &IsNew);
+ Succ->addPredecessor(Pred);
+
+ if (IsNew) {
+ Eng.WList->Enqueue(Succ);
+ return Succ;
+ }
+
+ return NULL;
+}
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(void* St, bool isSink) {
+
+ // Get the block for the default case.
+ assert (Src->succ_rbegin() != Src->succ_rend());
+ CFGBlock* DefaultBlock = *Src->succ_rbegin();
+
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src,
+ DefaultBlock),
+ St, &IsNew);
+ Succ->addPredecessor(Pred);
+
+ if (IsNew) {
+ if (isSink)
+ Succ->markAsSink();
+ else
+ Eng.WList->Enqueue(Succ);
+
+ return Succ;
+ }
+
+ return NULL;
+}
Modified: cfe/trunk/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRExprEngine.cpp?rev=47100&r1=47099&r2=47100&view=diff
==============================================================================
--- cfe/trunk/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/Analysis/GRExprEngine.cpp Wed Feb 13 17:08:21 2008
@@ -65,11 +65,15 @@
public:
typedef ValueStateManager::StateTy StateTy;
+ typedef ExplodedGraph<GRExprEngine> GraphTy;
+ typedef GraphTy::NodeTy NodeTy;
+
+ // Builders.
typedef GRStmtNodeBuilder<GRExprEngine> StmtNodeBuilder;
typedef GRBranchNodeBuilder<GRExprEngine> BranchNodeBuilder;
typedef GRIndirectGotoNodeBuilder<GRExprEngine> IndirectGotoNodeBuilder;
- typedef ExplodedGraph<GRExprEngine> GraphTy;
- typedef GraphTy::NodeTy NodeTy;
+ typedef GRSwitchNodeBuilder<GRExprEngine> SwitchNodeBuilder;
+
class NodeSet {
typedef llvm::SmallVector<NodeTy*,3> ImplTy;
@@ -197,6 +201,10 @@
/// nodes by processing the 'effects' of a computed goto jump.
void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
+ /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ void ProcessSwitch(SwitchNodeBuilder& builder);
+
/// RemoveDeadBindings - Return a new state that is the same as 'St' except
/// that all subexpression mappings are removed and that any
/// block-level expressions that are not live at 'S' also have their
@@ -474,6 +482,97 @@
builder.generateNode(I, St);
}
+/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+/// nodes by processing the 'effects' of a switch statement.
+void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
+
+ typedef SwitchNodeBuilder::iterator iterator;
+
+ StateTy St = builder.getState();
+ NonLValue CondV = cast<NonLValue>(GetValue(St, builder.getCondition()));
+
+ if (isa<UninitializedVal>(CondV)) {
+ NodeTy* N = builder.generateDefaultCaseNode(St, true);
+ UninitBranches.insert(N);
+ return;
+ }
+
+ StateTy DefaultSt = St;
+
+ // While most of this can be assumed (such as the signedness), having it
+ // just computed makes sure everything makes the same assumptions end-to-end.
+ unsigned bits = getContext().getTypeSize(getContext().IntTy,SourceLocation());
+ APSInt V1(bits, false);
+ APSInt V2 = V1;
+
+ for (iterator I=builder.begin(), E=builder.end(); I!=E; ++I) {
+
+ CaseStmt* Case = cast<CaseStmt>(I.getCase());
+
+ // Evaluate the case.
+ if (!Case->getLHS()->isIntegerConstantExpr(V1, getContext(), 0, true)) {
+ assert (false && "Case condition must evaluate to an integer constant.");
+ return;
+ }
+
+ // Get the RHS of the case, if it exists.
+
+ if (Expr* E = Case->getRHS()) {
+ if (!E->isIntegerConstantExpr(V2, getContext(), 0, true)) {
+ assert (false &&
+ "Case condition (RHS) must evaluate to an integer constant.");
+ return ;
+ }
+
+ assert (V1 <= V2);
+ }
+ else V2 = V1;
+
+ // FIXME: Eventually we should replace the logic below with a range
+ // comparison, rather than concretize the values within the range.
+ // This should be easy once we have "ranges" for NonLValues.
+
+ do {
+ nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1));
+
+ NonLValue Result =
+ CondV.EvalBinaryOp(ValMgr, BinaryOperator::EQ, CaseVal);
+
+ // Now "assume" that the case matches.
+ bool isFeasible;
+
+ StateTy StNew = Assume(St, Result, true, isFeasible);
+
+ if (isFeasible) {
+ builder.generateCaseStmtNode(I, StNew);
+
+ // If CondV evaluates to a constant, then we know that this
+ // is the *only* case that we can take, so stop evaluating the
+ // others.
+ if (isa<nonlval::ConcreteInt>(CondV))
+ return;
+ }
+
+ // Now "assume" that the case doesn't match. Add this state
+ // to the default state (if it is feasible).
+
+ StNew = Assume(DefaultSt, Result, false, isFeasible);
+
+ if (isFeasible)
+ DefaultSt = StNew;
+
+ // Concretize the next value in the range.
+ ++V1;
+
+ } while (V1 < V2);
+ }
+
+ // If we reach here, than we know that the default branch is
+ // possible.
+ builder.generateDefaultCaseNode(DefaultSt);
+}
+
+
void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
NodeSet& Dst) {
@@ -861,8 +960,8 @@
}
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
- GRExprEngine::NodeTy* Pred,
- GRExprEngine::NodeSet& Dst) {
+ GRExprEngine::NodeTy* Pred,
+ GRExprEngine::NodeSet& Dst) {
NodeSet S1;
if (B->isAssignmentOp())
@@ -1354,7 +1453,30 @@
Out << "\\|Terminator: ";
E.getSrc()->printTerminator(Out);
- if (isa<SwitchStmt>(T) || isa<IndirectGotoStmt>(T)) {
+ if (isa<SwitchStmt>(T)) {
+ Stmt* Label = E.getDst()->getLabel();
+
+ if (Label) {
+ if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+ Out << "\\lcase ";
+ C->getLHS()->printPretty(Out);
+
+ if (Stmt* RHS = C->getRHS()) {
+ Out << " .. ";
+ RHS->printPretty(Out);
+ }
+
+ Out << ":";
+ }
+ else {
+ assert (isa<DefaultStmt>(Label));
+ Out << "\\ldefault:";
+ }
+ }
+ else
+ Out << "\\l(implicit) default:";
+ }
+ else if (isa<IndirectGotoStmt>(T)) {
// FIXME
}
else {
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h?rev=47100&r1=47099&r2=47100&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h Wed Feb 13 17:08:21 2008
@@ -31,6 +31,7 @@
class GRStmtNodeBuilderImpl;
class GRBranchNodeBuilderImpl;
class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
class CFG;
class ASTContext;
class FunctionDecl;
@@ -43,6 +44,7 @@
friend class GRStmtNodeBuilderImpl;
friend class GRBranchNodeBuilderImpl;
friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
class NodeGroup {
enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
@@ -198,6 +200,7 @@
friend class GRStmtNodeBuilderImpl;
friend class GRBranchNodeBuilderImpl;
friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
// Type definitions.
typedef llvm::DenseMap<ProgramPoint,void*> EdgeNodeSetMap;
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h?rev=47100&r1=47099&r2=47100&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Wed Feb 13 17:08:21 2008
@@ -27,8 +27,8 @@
class GRStmtNodeBuilderImpl;
class GRBranchNodeBuilderImpl;
class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
class GRWorkList;
-class LabelStmt;
//===----------------------------------------------------------------------===//
/// GRCoreEngineImpl - Implements the core logic of the graph-reachability analysis.
@@ -44,6 +44,7 @@
friend class GRStmtNodeBuilderImpl;
friend class GRBranchNodeBuilderImpl;
friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
@@ -93,6 +94,8 @@
GRBranchNodeBuilderImpl& Builder) = 0;
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
private:
GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
@@ -331,6 +334,79 @@
return GRTrait<StateTy>::toState(NB.getState());
}
};
+
+class GRSwitchNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ Expr* Condition;
+ ExplodedNodeImpl* Pred;
+public:
+ GRSwitchNodeBuilderImpl(ExplodedNodeImpl* 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()); }
+
+ ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, void* State);
+ ExplodedNodeImpl* generateDefaultCaseNodeImpl(void* State, bool isSink);
+
+ inline Expr* getCondition() const { return Condition; }
+ inline void* getState() const { return Pred->State; }
+};
+
+template<typename CHECKER>
+class GRSwitchNodeBuilder {
+ typedef CHECKER CheckerTy;
+ typedef typename CheckerTy::StateTy StateTy;
+ typedef ExplodedGraph<CheckerTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRSwitchNodeBuilderImpl& NB;
+
+public:
+ GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
+
+ typedef GRSwitchNodeBuilderImpl::Iterator iterator;
+
+ inline iterator begin() { return NB.begin(); }
+ inline iterator end() { return NB.end(); }
+
+ inline Expr* getCondition() const { return NB.getCondition(); }
+
+ inline NodeTy* generateCaseStmtNode(const iterator& I, StateTy St) {
+ void *state = GRTrait<StateTy>::toPtr(St);
+ return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, state));
+ }
+
+ inline NodeTy* generateDefaultCaseNode(StateTy St, bool isSink = false) {
+ void *state = GRTrait<StateTy>::toPtr(St);
+ return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(state, isSink));
+ }
+
+ inline StateTy getState() const {
+ return GRTrait<StateTy>::toState(NB.getState());
+ }
+};
template<typename CHECKER>
@@ -371,6 +447,11 @@
Checker->ProcessIndirectGoto(Builder);
}
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
+ GRSwitchNodeBuilder<CHECKER> Builder(BuilderImpl);
+ Checker->ProcessSwitch(Builder);
+ }
+
public:
/// Construct a GRCoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph.
More information about the cfe-commits
mailing list