--- /dev/null
+//== BasicStore.h - Basic map from Locations to Values ----------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the BasicStore and BasicStoreManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BASICSTORE_H
+#define LLVM_CLANG_ANALYSIS_BASICSTORE_H
+
+#include "clang/Analysis/PathSensitive/Store.h"
+
+namespace llvm {
+ class llvm::BumpPtrAllocator;
+}
+
+namespace clang {
+ StoreManager* CreateBasicStoreManager(llvm::BumpPtrAllocator& Alloc);
+}
+
+#endif
/// with this node.
const ProgramPoint Location;
- /// State - The state associated with this node. Normally this value
- /// is immutable, but we anticipate there will be times when algorithms
- /// that directly manipulate the analysis graph will need to change it.
- void* State;
+ /// State - The state associated with this node.
+ const void* State;
/// Preds - The predecessors of this node.
NodeGroup Preds;
NodeGroup Succs;
/// Construct a ExplodedNodeImpl with the provided location and state.
- explicit ExplodedNodeImpl(const ProgramPoint& loc, void* state)
+ explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state)
: Location(loc), State(state) {}
/// addPredeccessor - Adds a predecessor to the current node, and
public:
/// Construct a ExplodedNodeImpl with the given node ID, program edge,
/// and state.
- explicit ExplodedNode(const ProgramPoint& loc, StateTy* St)
+ explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St)
: ExplodedNodeImpl(loc, St) {}
/// getState - Returns the state associated with the node.
- inline StateTy* getState() const {
- return static_cast<StateTy*>(State);
+ inline const StateTy* getState() const {
+ return static_cast<const StateTy*>(State);
}
// Profiling (for FoldingSet).
static inline void Profile(llvm::FoldingSetNodeID& ID,
const ProgramPoint& Loc,
- StateTy* state) {
+ const StateTy* state) {
ID.Add(Loc);
GRTrait<StateTy>::Profile(ID, state);
}
/// getNodeImpl - Retrieve the node associated with a (Location,State)
/// pair, where 'State' is represented as an opaque void*. This method
/// is intended to be used only by GRCoreEngineImpl.
- virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, void* State,
+ virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
+ const void* State,
bool* IsNew) = 0;
virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0;
protected:
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
- void* State, bool* IsNew) {
+ const void* State,
+ bool* IsNew) {
- return getNode(L, static_cast<StateTy*>(State), IsNew);
+ return getNode(L, static_cast<const StateTy*>(State), IsNew);
}
virtual ExplodedGraphImpl* MakeEmptyGraph() const {
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
/// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
- NodeTy* getNode(const ProgramPoint& L, StateTy* State, bool* IsNew = NULL) {
+ NodeTy* getNode(const ProgramPoint& L, const StateTy* State,
+ bool* IsNew = NULL) {
// Profile 'State' to determine if we already have an existing node.
llvm::FoldingSetNodeID profile;
/// number of times different CFGBlocks have been visited along a path.
GRBlockCounter::Factory BCounterFactory;
- void GenerateNode(const ProgramPoint& Loc, void* State,
+ void GenerateNode(const ProgramPoint& Loc, const void* State,
ExplodedNodeImpl* Pred = NULL);
/// 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 void* getInitialState() = 0;
+ virtual const void* getInitialState() = 0;
void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
- virtual bool ProcessBlockEntrance(CFGBlock* Blk, void* State,
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
GRBlockCounter BC) = 0;
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
}
ExplodedNodeImpl*
- generateNodeImpl(Stmt* S, void* State, ExplodedNodeImpl* Pred,
+ generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind);
ExplodedNodeImpl*
- generateNodeImpl(Stmt* S, void* State,
+ generateNodeImpl(Stmt* S, const void* State,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
ExplodedNodeImpl* N = getLastNode();
assert (N && "Predecessor of new node is infeasible.");
typedef ExplodedNode<StateTy> NodeTy;
GRStmtNodeBuilderImpl& NB;
- StateTy* CleanedState;
+ const StateTy* CleanedState;
GRAuditor<StateTy> **CallExprAuditBeg, **CallExprAuditEnd;
GRAuditor<StateTy> **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd;
}
NodeTy*
- generateNode(Stmt* S, StateTy* St, NodeTy* Pred,
+ generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
HasGeneratedNode = true;
}
NodeTy*
- generateNode(Stmt* S, StateTy* St,
+ generateNode(Stmt* S, const StateTy* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
HasGeneratedNode = true;
return NB.getCurrentBlockCount();
}
- StateTy* GetState(NodeTy* Pred) const {
+ const StateTy* GetState(NodeTy* Pred) const {
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
return CleanedState;
else
return Pred->getState();
}
- void SetCleanedState(StateTy* St) {
+ void SetCleanedState(const StateTy* St) {
CleanedState = St;
}
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
- NodeTy* Pred, StateTy* St) {
+ NodeTy* Pred, const StateTy* St) {
- StateTy* PredState = GetState(Pred);
+ const StateTy* PredState = GetState(Pred);
GRAuditor<StateTy> **AB = NULL, **AE = NULL;
const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
- ExplodedNodeImpl* generateNodeImpl(void* State, bool branch);
+ ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
CFGBlock* getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
return static_cast<NodeTy*>(NB.getPredecessor());
}
- StateTy* getState() const {
+ const StateTy* getState() const {
return getPredecessor()->getState();
}
- NodeTy* generateNode(StateTy* St, bool branch) {
+ NodeTy* generateNode(const StateTy* St, bool branch) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
}
Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
Iterator end() { return Iterator(DispatchBlock.succ_end()); }
- ExplodedNodeImpl* generateNodeImpl(const Iterator& I, void* State,
+ ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
bool isSink);
Expr* getTarget() const { return E; }
- void* getState() const { return Pred->State; }
+ const void* getState() const { return Pred->State; }
};
template<typename STATE>
Expr* getTarget() const { return NB.getTarget(); }
- NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){
+ NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
}
- StateTy* getState() const {
- return static_cast<StateTy*>(NB.getState());
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
}
};
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);
+ ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
+ const void* State);
+
+ ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
+ bool isSink);
Expr* getCondition() const { return Condition; }
- void* getState() const { return Pred->State; }
+ const void* getState() const { return Pred->State; }
};
template<typename STATE>
Expr* getCondition() const { return NB.getCondition(); }
- NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) {
+ NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
}
- NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) {
+ NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
}
- StateTy* getState() const {
- return static_cast<StateTy*>(NB.getState());
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
}
};
return getBlockCounter().getNumVisited(B.getBlockID());
}
- ExplodedNodeImpl* generateNodeImpl(void* State);
+ ExplodedNodeImpl* generateNodeImpl(const void* State);
CFGBlock* getBlock() const { return &B; }
};
return NB.getCurrentBlockCount();
}
- StateTy* getState() const {
+ const StateTy* getState() const {
return getPredecessor()->getState();
}
- NodeTy* MakeNode(StateTy* St) {
+ NodeTy* MakeNode(const StateTy* St) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St));
}
};
protected:
SubEngineTy& SubEngine;
- virtual void* getInitialState() {
+ virtual const void* getInitialState() {
return SubEngine.getInitialState();
}
SubEngine.ProcessStmt(S, Builder);
}
- virtual bool ProcessBlockEntrance(CFGBlock* Blk, void* State,
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
GRBlockCounter BC) {
- return SubEngine.ProcessBlockEntrance(Blk, static_cast<StateTy*>(State),BC);
+ return SubEngine.ProcessBlockEntrance(Blk,
+ static_cast<const StateTy*>(State),
+ BC);
}
virtual void ProcessBranch(Expr* Condition, Stmt* Terminator,
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
- ValueState* CleanedState;
+ const ValueState* CleanedState;
/// CurrentStmt - The current block-level statement.
Stmt* CurrentStmt;
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
- ValueState* getInitialState();
+ const ValueState* getInitialState();
GraphTy& getGraph() { return G; }
const GraphTy& getGraph() const { return G; }
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
- bool ProcessBlockEntrance(CFGBlock* B, ValueState* St, GRBlockCounter BC);
+ bool ProcessBlockEntrance(CFGBlock* B, const ValueState* St,
+ GRBlockCounter BC);
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
protected:
- ValueState* GetState(NodeTy* N) {
+ const ValueState* GetState(NodeTy* N) {
return N == EntryNode ? CleanedState : N->getState();
}
// FIXME: Maybe make these accesible only within the StmtBuilder?
- ValueState* SetRVal(ValueState* St, Expr* Ex, RVal V);
+ const ValueState* SetRVal(const ValueState* St, Expr* Ex, RVal V);
- ValueState* SetRVal(ValueState* St, const Expr* Ex, RVal V) {
+ const ValueState* SetRVal(const ValueState* St, const Expr* Ex, RVal V) {
return SetRVal(St, const_cast<Expr*>(Ex), V);
}
protected:
- ValueState* SetBlkExprRVal(ValueState* St, Expr* Ex, RVal V) {
+ const ValueState* SetBlkExprRVal(const ValueState* St, Expr* Ex, RVal V) {
return StateMgr.SetRVal(St, Ex, V, true, false);
}
- ValueState* SetRVal(ValueState* St, LVal LV, RVal V) {
+ const ValueState* SetRVal(const ValueState* St, LVal LV, RVal V) {
return StateMgr.SetRVal(St, LV, V);
}
- RVal GetRVal(ValueState* St, Expr* Ex) {
+ RVal GetRVal(const ValueState* St, Expr* Ex) {
return StateMgr.GetRVal(St, Ex);
}
- RVal GetRVal(ValueState* St, const Expr* Ex) {
+ RVal GetRVal(const ValueState* St, const Expr* Ex) {
return GetRVal(St, const_cast<Expr*>(Ex));
}
- RVal GetBlkExprRVal(ValueState* St, Expr* Ex) {
+ RVal GetBlkExprRVal(const ValueState* St, Expr* Ex) {
return StateMgr.GetBlkExprRVal(St, Ex);
}
- RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType()) {
+ RVal GetRVal(const ValueState* St, LVal LV, QualType T = QualType()) {
return StateMgr.GetRVal(St, LV, T);
}
/// Assume - Create new state by assuming that a given expression
/// is true or false.
- ValueState* Assume(ValueState* St, RVal Cond, bool Assumption,
- bool& isFeasible) {
+ const ValueState* Assume(const ValueState* St, RVal Cond, bool Assumption,
+ bool& isFeasible) {
if (Cond.isUnknown()) {
isFeasible = true;
return Assume(St, cast<NonLVal>(Cond), Assumption, isFeasible);
}
- ValueState* Assume(ValueState* St, LVal Cond, bool Assumption,
- bool& isFeasible);
+ const ValueState* Assume(const ValueState* St, LVal Cond, bool Assumption,
+ bool& isFeasible);
- ValueState* AssumeAux(ValueState* St, LVal Cond, bool Assumption,
- bool& isFeasible);
+ const ValueState* AssumeAux(const ValueState* St, LVal Cond, bool Assumption,
+ bool& isFeasible);
- ValueState* Assume(ValueState* St, NonLVal Cond, bool Assumption,
- bool& isFeasible);
+ const ValueState* Assume(const ValueState* St, NonLVal Cond, bool Assumption,
+ bool& isFeasible);
- ValueState* AssumeAux(ValueState* St, NonLVal Cond, bool Assumption,
- bool& isFeasible);
+ const ValueState* AssumeAux(const ValueState* St, NonLVal Cond,
+ bool Assumption, bool& isFeasible);
- ValueState* AssumeSymNE(ValueState* St, SymbolID sym, const llvm::APSInt& V,
- bool& isFeasible);
+ const ValueState* AssumeSymNE(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V, bool& isFeasible);
- ValueState* AssumeSymEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V,
- bool& isFeasible);
+ const ValueState* AssumeSymEQ(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V, bool& isFeasible);
- ValueState* AssumeSymInt(ValueState* St, bool Assumption,
- const SymIntConstraint& C, bool& isFeasible);
+ const ValueState* AssumeSymInt(const ValueState* St, bool Assumption,
+ const SymIntConstraint& C, bool& isFeasible);
- NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, ValueState* St) {
+ NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const ValueState* St) {
assert (Builder && "GRStmtNodeBuilder not present.");
return Builder->MakeNode(Dst, S, Pred, St);
}
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
bool asLVal);
- bool CheckDivideZero(Expr* Ex, ValueState* St, NodeTy* Pred, RVal Denom);
+ bool CheckDivideZero(Expr* Ex, const ValueState* St, NodeTy* Pred,
+ RVal Denom);
RVal EvalCast(RVal X, QualType CastT) {
if (X.isUnknownOrUndef())
TF->EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
}
- void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* St,
+ void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const ValueState* St,
RVal TargetLV, RVal Val);
// FIXME: The "CheckOnly" option exists only because Array and Field
// loads aren't fully implemented. Eventually this option will go away.
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
- ValueState* St, RVal location, bool CheckOnly = false);
+ const ValueState* St, RVal location, bool CheckOnly = false);
- ValueState* EvalLocation(Expr* Ex, NodeTy* Pred,
- ValueState* St, RVal location, bool isLoad = false);
+ const ValueState* EvalLocation(Expr* Ex, NodeTy* Pred,
+ const ValueState* St, RVal location,
+ bool isLoad = false);
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
- ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
+ const ValueState* MarkBranch(const ValueState* St, Stmt* Terminator, bool branchTaken);
};
} // end clang namespace
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
Expr* E, ExplodedNode<ValueState>* Pred,
- ValueState* St, RVal TargetLV, RVal Val);
+ const ValueState* St, RVal TargetLV, RVal Val);
// End-of-path and dead symbol notification.
GRStmtNodeBuilder<ValueState>& Builder,
ExplodedNode<ValueState>* Pred,
Stmt* S,
- ValueState* St,
+ const ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead) {}
// Return statements.
// Assumptions.
- virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
- RVal Cond, bool Assumption, bool& isFeasible) {
+ virtual const ValueState* EvalAssume(GRExprEngine& Engine,
+ const ValueState* St,
+ RVal Cond, bool Assumption,
+ bool& isFeasible) {
return St;
}
};
--- /dev/null
+//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_STORE_H
+#define LLVM_CLANG_ANALYSIS_STORE_H
+
+#include "clang/Analysis/PathSensitive/RValues.h"
+
+namespace clang {
+
+typedef const void* Store;
+
+class StoreManager {
+public:
+ virtual ~StoreManager() {}
+ virtual RVal GetRVal(Store St, LVal LV, QualType T) = 0;
+ virtual Store SetRVal(Store St, LVal LV, RVal V) = 0;
+ virtual Store Remove(Store St, LVal LV) = 0;
+ virtual Store getInitialStore() = 0;
+};
+
+} // end clang namespace
+
+#endif
// FIXME: Reduce the number of includes.
#include "clang/Analysis/PathSensitive/Environment.h"
+#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/RValues.h"
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
#include "clang/AST/Expr.h"
public:
// Typedefs.
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
- typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
typedef llvm::ImmutableMap<SymbolID,IntSetTy> ConstNotEqTy;
typedef llvm::ImmutableMap<SymbolID,const llvm::APSInt*> ConstEqTy;
friend class ValueStateManager;
Environment Env;
+ Store St;
// FIXME: Make these private.
public:
- VarBindingsTy VarBindings;
ConstNotEqTy ConstNotEq;
ConstEqTy ConstEq;
void* CheckerState;
public:
/// This ctor is used when creating the first ValueState object.
- ValueState(const Environment& env, VarBindingsTy VB,
+ ValueState(const Environment& env, Store st,
ConstNotEqTy CNE, ConstEqTy CE)
: Env(env),
- VarBindings(VB),
+ St(st),
ConstNotEq(CNE),
ConstEq(CE),
CheckerState(NULL) {}
ValueState(const ValueState& RHS)
: llvm::FoldingSetNode(),
Env(RHS.Env),
- VarBindings(RHS.VarBindings),
+ St(RHS.St),
ConstNotEq(RHS.ConstNotEq),
ConstEq(RHS.ConstEq),
CheckerState(RHS.CheckerState) {}
/// The environment is the mapping from expressions to values.
const Environment& getEnvironment() const { return Env; }
+ /// getStore - Return the store associated with this state. The store
+ /// is a mapping from locations to values.
+ Store getStore() const { return St; }
+
/// Profile - Profile the contents of a ValueState object for use
/// in a FoldingSet.
static void Profile(llvm::FoldingSetNodeID& ID, const ValueState* V) {
V->Env.Profile(ID);
- V->VarBindings.Profile(ID);
+ ID.AddPointer(V->St);
V->ConstNotEq.Profile(ID);
V->ConstEq.Profile(ID);
ID.AddPointer(V->CheckerState);
// Iterators.
+ // FIXME: We'll be removing the VarBindings iterator very soon. Right now
+ // it assumes that Store is a VarBindingsTy.
+ typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
typedef VarBindingsTy::iterator vb_iterator;
- vb_iterator vb_begin() const { return VarBindings.begin(); }
- vb_iterator vb_end() const { return VarBindings.end(); }
+ vb_iterator vb_begin() const {
+ VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
+ return B.begin();
+ }
+ vb_iterator vb_end() const {
+ VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
+ return B.end();
+ }
typedef Environment::seb_iterator seb_iterator;
seb_iterator seb_begin() const { return Env.seb_begin(); }
class ValueStateManager {
private:
EnvironmentManager EnvMgr;
+ llvm::OwningPtr<StoreManager> StMgr;
ValueState::IntSetTy::Factory ISetFactory;
- ValueState::VarBindingsTy::Factory VBFactory;
ValueState::ConstNotEqTy::Factory CNEFactory;
ValueState::ConstEqTy::Factory CEFactory;
Environment RemoveBlkExpr(const Environment& Env, Expr* E) {
return EnvMgr.RemoveBlkExpr(Env, E);
}
-
- ValueState::VarBindingsTy Remove(ValueState::VarBindingsTy B, VarDecl* V) {
- return VBFactory.Remove(B, V);
- }
-
- ValueState::VarBindingsTy Remove(const ValueState& V, VarDecl* D) {
- return Remove(V.VarBindings, D);
+
+ // FIXME: Remove when we do lazy initializaton of variable bindings.
+ const ValueState* BindVar(const ValueState* St, VarDecl* D, RVal V) {
+ return SetRVal(St, lval::DeclVal(D), V);
}
-
- ValueState* BindVar(ValueState* St, VarDecl* D, RVal V);
- ValueState* UnbindVar(ValueState* St, VarDecl* D);
-
+
public:
- ValueStateManager(ASTContext& Ctx, llvm::BumpPtrAllocator& alloc)
- : EnvMgr(alloc),
- ISetFactory(alloc),
- VBFactory(alloc),
- CNEFactory(alloc),
- CEFactory(alloc),
- BasicVals(Ctx, alloc),
- SymMgr(alloc),
- Alloc(alloc) {}
-
- ValueState* getInitialState();
+ ValueStateManager(ASTContext& Ctx, StoreManager* stmgr,
+ llvm::BumpPtrAllocator& alloc)
+ : EnvMgr(alloc),
+ StMgr(stmgr),
+ ISetFactory(alloc),
+ CNEFactory(alloc),
+ CEFactory(alloc),
+ BasicVals(Ctx, alloc),
+ SymMgr(alloc),
+ Alloc(alloc) {}
+
+ const ValueState* getInitialState();
BasicValueFactory& getBasicValueFactory() { return BasicVals; }
SymbolManager& getSymbolManager() { return SymMgr; }
typedef llvm::DenseSet<SymbolID> DeadSymbolsTy;
- ValueState* RemoveDeadBindings(ValueState* St, Stmt* Loc,
- const LiveVariables& Liveness,
- DeadSymbolsTy& DeadSymbols);
+ const ValueState* RemoveDeadBindings(const ValueState* St, Stmt* Loc,
+ const LiveVariables& Liveness,
+ DeadSymbolsTy& DeadSymbols);
- ValueState* RemoveSubExprBindings(ValueState* St) {
+ const ValueState* RemoveSubExprBindings(const ValueState* St) {
ValueState NewSt = *St;
NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
- return getPersistentState(NewSt);
+ return getPersistentState(NewSt);
}
// Methods that query & manipulate the Environment.
- RVal GetRVal(ValueState* St, Expr* Ex) {
+ RVal GetRVal(const ValueState* St, Expr* Ex) {
return St->getEnvironment().GetRVal(Ex, BasicVals);
}
- RVal GetBlkExprRVal(ValueState* St, Expr* Ex) {
+ RVal GetBlkExprRVal(const ValueState* St, Expr* Ex) {
return St->getEnvironment().GetBlkExprRVal(Ex, BasicVals);
}
- ValueState* SetRVal(ValueState* St, Expr* Ex, RVal V, bool isBlkExpr,
- bool Invalidate) {
+ const ValueState* SetRVal(const ValueState* St, Expr* Ex, RVal V,
+ bool isBlkExpr, bool Invalidate) {
const Environment& OldEnv = St->getEnvironment();
Environment NewEnv = EnvMgr.SetRVal(OldEnv, Ex, V, isBlkExpr, Invalidate);
// Methods that query & manipulate the Store.
- RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
+ RVal GetRVal(const ValueState* St, LVal LV, QualType T = QualType()) {
+ return StMgr->GetRVal(St->getStore(), LV, T);
+ }
- ValueState* SetRVal(ValueState* St, LVal LV, RVal V);
+ void SetRVal(ValueState& St, LVal LV, RVal V) {
+ St.St = StMgr->SetRVal(St.St, LV, V);
+ }
+
+ const ValueState* SetRVal(const ValueState* St, LVal LV, RVal V);
- void BindVar(ValueState& StImpl, VarDecl* D, RVal V);
+ void Unbind(ValueState& St, LVal LV) {
+ St.St = StMgr->Remove(St.St, LV);
+ }
- void Unbind(ValueState& StImpl, LVal LV);
+ const ValueState* Unbind(const ValueState* St, LVal LV);
- ValueState* getPersistentState(ValueState& Impl);
+ const ValueState* getPersistentState(ValueState& Impl);
- ValueState* AddEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V);
- ValueState* AddNE(ValueState* St, SymbolID sym, const llvm::APSInt& V);
+ const ValueState* AddEQ(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V);
+
+ const ValueState* AddNE(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V);
};
} // end clang namespace
typedef std::vector<BugReport*> ErrorsTy;
ErrorsTy Errors;
- RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
+ RVal GetRVal(const ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
bool isNSString(ObjCInterfaceType* T, const char* suffix);
bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
IdentifierInfo* II;
ValueStateManager* VMgr;
- RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
- RVal GetRVal(ValueState* St, LVal LV) { return VMgr->GetRVal(St, LV); }
+ RVal GetRVal(const ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
+ RVal GetRVal(const ValueState* St, LVal LV) { return VMgr->GetRVal(St, LV); }
public:
--- /dev/null
+//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the BasicStore and BasicStoreManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BasicStore.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+
+class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
+ typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
+ VarBindingsTy::Factory VBFactory;
+
+public:
+ BasicStoreManager(llvm::BumpPtrAllocator& A) : VBFactory(A) {}
+ virtual ~BasicStoreManager() {}
+
+ virtual RVal GetRVal(Store St, LVal LV, QualType T);
+ virtual Store SetRVal(Store St, LVal LV, RVal V);
+ virtual Store Remove(Store St, LVal LV);
+
+ virtual Store getInitialStore() {
+ return VBFactory.GetEmptyMap().getRoot();
+ }
+};
+
+} // end anonymous namespace
+
+
+StoreManager* clang::CreateBasicStoreManager(llvm::BumpPtrAllocator& A) {
+ return new BasicStoreManager(A);
+}
+
+RVal BasicStoreManager::GetRVal(Store St, LVal LV, QualType T) {
+
+ if (isa<UnknownVal>(LV))
+ return UnknownVal();
+
+ assert (!isa<UndefinedVal>(LV));
+
+ switch (LV.getSubKind()) {
+
+ case lval::DeclValKind: {
+ VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
+ VarBindingsTy::data_type* T = B.lookup(cast<lval::DeclVal>(LV).getDecl());
+ return T ? *T : UnknownVal();
+ }
+
+ case lval::SymbolValKind: {
+
+ // FIXME: This is a broken representation of memory, and is prone
+ // to crashing the analyzer when addresses to symbolic values are
+ // passed through casts. We need a better representation of symbolic
+ // memory (or just memory in general); probably we should do this
+ // as a plugin class (similar to GRTransferFuncs).
+
+#if 0
+ const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
+ assert (T.getTypePtr());
+
+ // Punt on "symbolic" function pointers.
+ if (T->isFunctionType())
+ return UnknownVal();
+
+ if (T->isPointerType())
+ return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+ else
+ return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+#endif
+
+ return UnknownVal();
+ }
+
+ case lval::ConcreteIntKind:
+ // Some clients may call GetRVal with such an option simply because
+ // they are doing a quick scan through their LVals (potentially to
+ // invalidate their bindings). Just return Undefined.
+ return UndefinedVal();
+
+ case lval::ArrayOffsetKind:
+ case lval::FieldOffsetKind:
+ return UnknownVal();
+
+ case lval::FuncValKind:
+ return LV;
+
+ case lval::StringLiteralValKind:
+ // FIXME: Implement better support for fetching characters from strings.
+ return UnknownVal();
+
+ default:
+ assert (false && "Invalid LVal.");
+ break;
+ }
+
+ return UnknownVal();
+}
+
+Store BasicStoreManager::SetRVal(Store St, LVal LV, RVal V) {
+
+ VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
+
+ switch (LV.getSubKind()) {
+
+ case lval::DeclValKind:
+ return V.isUnknown()
+ ? VBFactory.Remove(B,cast<lval::DeclVal>(LV).getDecl()).getRoot()
+ : VBFactory.Add(B, cast<lval::DeclVal>(LV).getDecl(), V).getRoot();
+
+ default:
+ assert ("SetRVal for given LVal type not yet implemented.");
+ return St;
+ }
+}
+
+Store BasicStoreManager::Remove(Store St, LVal LV) {
+
+ VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
+
+ switch (LV.getSubKind()) {
+
+ case lval::DeclValKind:
+ return VBFactory.Remove(B,cast<lval::DeclVal>(LV).getDecl()).getRoot();
+
+ default:
+ assert ("Remove for given LVal type not yet implemented.");
+ return St;
+ }
+}
PathDiagnostic& PD) {
ExplodedNode<ValueState>* Pred = N->pred_empty() ? 0 : *N->pred_begin();
- ValueState* PrevSt = Pred ? Pred->getState() : 0;
+ const ValueState* PrevSt = Pred ? Pred->getState() : 0;
if (!PrevSt)
return;
// Look at the variable bindings of the current state that map to the
// specified symbol. Are any of them not in the previous state.
- ValueState* St = N->getState();
+ const ValueState* St = N->getState();
ValueStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
// FIXME: Later generalize for a broader memory model.
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
- ValueState* St = N->getState();
+ const ValueState* St = N->getState();
// Scan the lval bindings, and see if a "notable" symbol has a new
// lval binding.
public:
- static RefBindings GetRefBindings(ValueState& StImpl) {
- return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
+ static RefBindings GetRefBindings(const ValueState& StImpl) {
+ return RefBindings((const RefBindings::TreeTy*) StImpl.CheckerState);
}
private:
GRStmtNodeBuilder<ValueState>& Builder,
Expr* NodeExpr, Expr* ErrorExpr,
ExplodedNode<ValueState>* Pred,
- ValueState* St,
+ const ValueState* St,
RefVal::Kind hasErr, SymbolID Sym);
- ValueState* HandleSymbolDeath(ValueStateManager& VMgr, ValueState* St,
- SymbolID sid, RefVal V, bool& hasLeak);
+ const ValueState* HandleSymbolDeath(ValueStateManager& VMgr,
+ const ValueState* St,
+ SymbolID sid, RefVal V, bool& hasLeak);
- ValueState* NukeBinding(ValueStateManager& VMgr, ValueState* St,
- SymbolID sid);
+ const ValueState* NukeBinding(ValueStateManager& VMgr, const ValueState* St,
+ SymbolID sid);
public:
GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
Expr* E, ExplodedNode<ValueState>* Pred,
- ValueState* St, RVal TargetLV, RVal Val);
+ const ValueState* St, RVal TargetLV, RVal Val);
// End-of-path.
virtual void EvalEndPath(GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
ExplodedNode<ValueState>* Pred,
Stmt* S,
- ValueState* St,
+ const ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead);
// Return statements.
// Assumptions.
- virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
- RVal Cond, bool Assumption, bool& isFeasible);
+ virtual const ValueState* EvalAssume(GRExprEngine& Engine,
+ const ValueState* St, RVal Cond,
+ bool Assumption, bool& isFeasible);
// Error iterators.
GRStmtNodeBuilder<ValueState>& Builder,
Expr* NodeExpr, Expr* ErrorExpr,
ExplodedNode<ValueState>* Pred,
- ValueState* St,
+ const ValueState* St,
RefVal::Kind hasErr, SymbolID Sym) {
Builder.BuildSinks = true;
GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
// Get the state.
ValueStateManager& StateMgr = Eng.getStateManager();
- ValueState* St = Builder.GetState(Pred);
+ const ValueState* St = Builder.GetState(Pred);
// Evaluate the effect of the arguments.
ValueState StVals = *St;
unsigned Count = Builder.getCurrentBlockCount();
SymbolID NewSym = Eng.getSymbolManager().getConjuredSymbol(*I, Count);
- StateMgr.BindVar(StVals, DV->getDecl(),
+ StateMgr.SetRVal(StVals, *DV,
LVal::IsLValType(DV->getDecl()->getType())
? cast<RVal>(lval::SymbolVal(NewSym))
: cast<RVal>(nonlval::SymbolVal(NewSym)));
// FIXME: Wouldn't it be great if this code could be reduced? It's just
// a chain of lookups.
- ValueState* St = Builder.GetState(Pred);
+ const ValueState* St = Builder.GetState(Pred);
RVal V = Eng.getStateManager().GetRVal(St, Receiver );
if (isa<lval::SymbolVal>(V)) {
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
Expr* E, ExplodedNode<ValueState>* Pred,
- ValueState* St, RVal TargetLV, RVal Val) {
+ const ValueState* St, RVal TargetLV, RVal Val) {
// Check if we have a binding for "Val" and if we are storing it to something
// we don't understand or otherwise the value "escapes" the function.
}
-ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
- SymbolID sid) {
+const ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr,
+ const ValueState* St,
+ SymbolID sid) {
ValueState StImpl = *St;
RefBindings B = GetRefBindings(StImpl);
StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot();
// End-of-path.
-ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
- ValueState* St, SymbolID sid,
+const ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
+ const ValueState* St, SymbolID sid,
RefVal V, bool& hasLeak) {
hasLeak = V.isOwned() ||
void CFRefCount::EvalEndPath(GRExprEngine& Eng,
GREndPathNodeBuilder<ValueState>& Builder) {
- ValueState* St = Builder.getState();
+ const ValueState* St = Builder.getState();
RefBindings B = GetRefBindings(*St);
llvm::SmallVector<SymbolID, 10> Leaked;
GRStmtNodeBuilder<ValueState>& Builder,
ExplodedNode<ValueState>* Pred,
Stmt* S,
- ValueState* St,
+ const ValueState* St,
const ValueStateManager::DeadSymbolsTy& Dead) {
// FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
if (!RetE) return;
ValueStateManager& StateMgr = Eng.getStateManager();
- ValueState* St = Builder.GetState(Pred);
+ const ValueState* St = Builder.GetState(Pred);
RVal V = StateMgr.GetRVal(St, RetE);
if (!isa<lval::SymbolVal>(V))
// Assumptions.
-ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng, ValueState* St,
- RVal Cond, bool Assumption,
- bool& isFeasible) {
+const ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng,
+ const ValueState* St,
+ RVal Cond, bool Assumption,
+ bool& isFeasible) {
// FIXME: We may add to the interface of EvalAssume the list of symbols
// whose assumptions have changed. For now we just iterate through the
// Check if the type state has changed.
- ValueState* PrevSt = PrevN->getState();
- ValueState* CurrSt = N->getState();
+ const ValueState* PrevSt = PrevN->getState();
+ const ValueState* CurrSt = N->getState();
CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt);
CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt);
VarDecl* FirstDecl = 0;
while (N) {
- ValueState* St = N->getState();
+ const ValueState* St = N->getState();
RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
if (!B.lookup(Sym))
/// GenerateNode - Utility method to generate nodes, hook up successors,
/// and add nodes to the worklist.
-void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, void* State,
- ExplodedNodeImpl* Pred) {
+void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, const void* State,
+ ExplodedNodeImpl* Pred) {
bool IsNew;
ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew);
}
ExplodedNodeImpl*
-GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
+GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, const void* State,
ExplodedNodeImpl* Pred,
ProgramPoint::Kind K) {
return NULL;
}
-ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(void* State,
+ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(const void* State,
bool branch) {
bool IsNew;
ExplodedNodeImpl*
GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Iterator& I,
- void* St,
+ const void* St,
bool isSink) {
bool IsNew;
ExplodedNodeImpl*
-GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, void* St) {
+GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I,
+ const void* St) {
bool IsNew;
ExplodedNodeImpl*
-GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(void* St, bool isSink) {
+GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(const void* St,
+ bool isSink) {
// Get the block for the default case.
assert (Src->succ_rbegin() != Src->succ_rend());
if (!HasGeneratedNode) generateNodeImpl(Pred->State);
}
-ExplodedNodeImpl* GREndPathNodeBuilderImpl::generateNodeImpl(void* State) {
+ExplodedNodeImpl* GREndPathNodeBuilderImpl::generateNodeImpl(const void* State){
HasGeneratedNode = true;
bool IsNew;
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Streams.h"
+#include "clang/Analysis/PathSensitive/BasicStore.h"
+
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#include <sstream>
G(CoreEngine.getGraph()),
Liveness(L),
Builder(NULL),
- StateMgr(G.getContext(), G.getAllocator()),
+ StateMgr(G.getContext(), CreateBasicStoreManager(G.getAllocator()),
+ G.getAllocator()),
BasicVals(StateMgr.getBasicValueFactory()),
TF(NULL), // FIXME
SymMgr(StateMgr.getSymbolManager()),
MsgExprChecks.push_back(A);
}
-ValueState* GRExprEngine::getInitialState() {
+const ValueState* GRExprEngine::getInitialState() {
// The LiveVariables information already has a compilation of all VarDecls
// used in the function. Iterate through this set, and "symbolicate"
if (VarDecl* VD = dyn_cast<VarDecl>(SD)) {
if (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD)) {
RVal X = RVal::GetSymbolValue(SymMgr, VD);
- StateMgr.BindVar(StateImpl, VD, X);
+ StateMgr.SetRVal(StateImpl, lval::DeclVal(VD), X);
}
} else if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(SD)) {
RVal X = RVal::GetSymbolValue(SymMgr, IPD);
- StateMgr.BindVar(StateImpl, IPD, X);
+ StateMgr.SetRVal(StateImpl, lval::DeclVal(IPD), X);
}
return StateMgr.getPersistentState(StateImpl);
}
-ValueState* GRExprEngine::SetRVal(ValueState* St, Expr* Ex, RVal V) {
+const ValueState* GRExprEngine::SetRVal(const ValueState* St, Expr* Ex,
+ RVal V) {
bool isBlkExpr = false;
break;
}
else if (B->getOpcode() == BinaryOperator::Comma) {
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
MakeNode(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS())));
break;
}
case Stmt::StmtExprClass: {
StmtExpr* SE = cast<StmtExpr>(S);
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
// FIXME: Not certain if we can have empty StmtExprs. If so, we should
// probably just remove these from the CFG.
// Block entrance. (Update counters).
//===----------------------------------------------------------------------===//
-bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, ValueState*,
+bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ValueState*,
GRBlockCounter BC) {
return BC.getNumVisited(B->getBlockID()) < 3;
// Branch processing.
//===----------------------------------------------------------------------===//
-ValueState* GRExprEngine::MarkBranch(ValueState* St, Stmt* Terminator,
- bool branchTaken) {
+const ValueState* GRExprEngine::MarkBranch(const ValueState* St,
+ Stmt* Terminator,
+ bool branchTaken) {
switch (Terminator->getStmtClass()) {
default:
BranchNodeBuilder& builder) {
// Remove old bindings for subexpressions.
- ValueState* PrevState = StateMgr.RemoveSubExprBindings(builder.getState());
+ const ValueState* PrevState =
+ StateMgr.RemoveSubExprBindings(builder.getState());
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
// Process the true branch.
bool isFeasible = false;
- ValueState* St = Assume(PrevState, V, true, isFeasible);
+ const ValueState* St = Assume(PrevState, V, true, isFeasible);
if (isFeasible)
builder.generateNode(MarkBranch(St, Term, true), true);
/// nodes by processing the 'effects' of a computed goto jump.
void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
- ValueState* St = builder.getState();
+ const ValueState* St = builder.getState();
RVal V = GetRVal(St, builder.getTarget());
// Three possibilities:
assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex));
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
RVal X = GetBlkExprRVal(St, Ex);
assert (X.isUndef());
typedef SwitchNodeBuilder::iterator iterator;
- ValueState* St = builder.getState();
+ const ValueState* St = builder.getState();
Expr* CondE = builder.getCondition();
RVal CondV = GetRVal(St, CondE);
return;
}
- ValueState* DefaultSt = St;
+ const ValueState* 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.
// Now "assume" that the case matches.
bool isFeasible = false;
- ValueState* StNew = Assume(St, Res, true, isFeasible);
+ const ValueState* StNew = Assume(St, Res, true, isFeasible);
if (isFeasible) {
builder.generateCaseStmtNode(I, StNew);
assert (B == CurrentStmt && getCFG().isBlkExpr(B));
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
RVal X = GetBlkExprRVal(St, B);
assert (X.isUndef());
// the payoff is not likely to be large. Instead, we do eager evaluation.
bool isFeasible = false;
- ValueState* NewState = Assume(St, X, true, isFeasible);
+ const ValueState* NewState = Assume(St, X, true, isFeasible);
if (isFeasible)
MakeNode(Dst, B, Pred,
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst,
bool asLVal) {
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
RVal X = RVal::MakeVal(BasicVals, D);
if (asLVal)
for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) {
- ValueState* St = GetState(*I2);
+ const ValueState* St = GetState(*I2);
RVal BaseV = GetRVal(St, Base);
RVal IdxV = GetRVal(St, Idx);
VisitLVal(Base, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal BaseV = GetRVal(St, Base);
RVal V = lval::FieldOffset::Make(BasicVals, GetRVal(St, Base),
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal BaseV = GetRVal(St, Base);
if (LVal::IsLValType(Base->getType())) {
}
void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
- ValueState* St, RVal location, RVal Val) {
+ const ValueState* St, RVal location, RVal Val) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
}
void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
- ValueState* St, RVal location, bool CheckOnly) {
+ const ValueState* St, RVal location,
+ bool CheckOnly) {
// Evaluate the location (checks for bad dereferences).
Ex->getType())));
}
-ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
- ValueState* St, RVal location,
- bool isLoad) {
+const ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
+ const ValueState* St,
+ RVal location, bool isLoad) {
// Check for loads/stores from/to undefined values.
if (location.isUndef()) {
// "Assume" that the pointer is not NULL.
bool isFeasibleNotNull = false;
- ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
+ const ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
// "Assume" that the pointer is NULL.
bool isFeasibleNull = false;
- ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
+ const ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
if (isFeasibleNull) {
// Finally, evaluate the function call.
for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
- ValueState* St = GetState(*DI);
+ const ValueState* St = GetState(*DI);
RVal L = GetRVal(St, Callee);
// FIXME: Add support for symbolic function calls (calls involving
// FIXME: More logic for the processing the method call.
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
bool RaisesException = false;
for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
NodeTy* N = *I1;
- ValueState* St = GetState(N);
+ const ValueState* St = GetState(N);
RVal V = GetRVal(St, Ex);
// Unknown?
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
if (!Ex && VD->hasGlobalStorage()) {
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal location = GetRVal(St, Ex);
if (asLVal)
// For all other types, UnaryOperator::Real is an identity operation.
assert (U->getType() == Ex->getType());
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
MakeNode(Dst, U, *I, SetRVal(St, U, GetRVal(St, Ex)));
}
// For all other types, UnaryOperator::Float returns 0.
assert (Ex->getType()->isIntegerType());
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal X = NonLVal::MakeVal(BasicVals, 0, Ex->getType());
MakeNode(Dst, U, *I, SetRVal(St, U, X));
}
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
MakeNode(Dst, U, *I, SetRVal(St, U, GetRVal(St, Ex)));
}
VisitLVal(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal V = GetRVal(St, Ex);
St = SetRVal(St, U, V);
MakeNode(Dst, U, *I, St);
Visit(Ex, Pred, Tmp);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal V = GetRVal(St, Ex);
if (V.isUnknownOrUndef()) {
return;
uint64_t size = getContext().getTypeSize(T) / 8;
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType()));
MakeNode(Dst, U, Pred, St);
for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
+ const ValueState* St = GetState(*I);
RVal V1 = GetRVal(St, Ex);
// Perform a load.
// which interprets the inline asm and stores proper results in the
// outputs.
- ValueState* St = GetState(Pred);
+ const ValueState* St = GetState(Pred);
for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//
-bool GRExprEngine::CheckDivideZero(Expr* Ex, ValueState* St,
+bool GRExprEngine::CheckDivideZero(Expr* Ex, const ValueState* St,
NodeTy* Pred, RVal Denom) {
// Divide by undefined? (potentially zero)
// First, "assume" that the denominator is 0 or undefined.
bool isFeasibleZero = false;
- ValueState* ZeroSt = Assume(St, Denom, false, isFeasibleZero);
+ const ValueState* ZeroSt = Assume(St, Denom, false, isFeasibleZero);
// Second, "assume" that the denominator cannot be 0.
for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2 != E2; ++I2) {
- ValueState* St = GetState(*I2);
+ const ValueState* St = GetState(*I2);
RVal RightV = GetRVal(St, RHS);
BinaryOperator::Opcode Op = B->getOpcode();
// "Assume" logic.
//===----------------------------------------------------------------------===//
-ValueState* GRExprEngine::Assume(ValueState* St, LVal Cond,
- bool Assumption, bool& isFeasible) {
+const ValueState* GRExprEngine::Assume(const ValueState* St, LVal Cond,
+ bool Assumption, bool& isFeasible) {
St = AssumeAux(St, Cond, Assumption, isFeasible);
: St;
}
-ValueState* GRExprEngine::AssumeAux(ValueState* St, LVal Cond,
- bool Assumption, bool& isFeasible) {
+const ValueState* GRExprEngine::AssumeAux(const ValueState* St, LVal Cond,
+ bool Assumption, bool& isFeasible) {
switch (Cond.getSubKind()) {
default:
}
}
-ValueState* GRExprEngine::Assume(ValueState* St, NonLVal Cond,
- bool Assumption, bool& isFeasible) {
+const ValueState* GRExprEngine::Assume(const ValueState* St, NonLVal Cond,
+ bool Assumption, bool& isFeasible) {
St = AssumeAux(St, Cond, Assumption, isFeasible);
: St;
}
-ValueState* GRExprEngine::AssumeAux(ValueState* St, NonLVal Cond,
- bool Assumption, bool& isFeasible) {
+const ValueState* GRExprEngine::AssumeAux(const ValueState* St, NonLVal Cond,
+ bool Assumption, bool& isFeasible) {
switch (Cond.getSubKind()) {
default:
assert (false && "'Assume' not implemented for this NonLVal.");
}
}
-ValueState*
-GRExprEngine::AssumeSymNE(ValueState* St, SymbolID sym,
- const llvm::APSInt& V, bool& isFeasible) {
+const ValueState* GRExprEngine::AssumeSymNE(const ValueState* St,
+ SymbolID sym, const llvm::APSInt& V,
+ bool& isFeasible) {
// First, determine if sym == X, where X != V.
if (const llvm::APSInt* X = St->getSymVal(sym)) {
return StateMgr.AddNE(St, sym, V);
}
-ValueState*
-GRExprEngine::AssumeSymEQ(ValueState* St, SymbolID sym,
- const llvm::APSInt& V, bool& isFeasible) {
+const ValueState* GRExprEngine::AssumeSymEQ(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V, bool& isFeasible) {
// First, determine if sym == X, where X != V.
if (const llvm::APSInt* X = St->getSymVal(sym)) {
return StateMgr.AddEQ(St, sym, V);
}
-ValueState*
-GRExprEngine::AssumeSymInt(ValueState* St, bool Assumption,
- const SymIntConstraint& C, bool& isFeasible) {
+const ValueState* GRExprEngine::AssumeSymInt(const ValueState* St,
+ bool Assumption,
+ const SymIntConstraint& C,
+ bool& isFeasible) {
switch (C.getOpcode()) {
default:
struct VISIBILITY_HIDDEN FindUndefExpr {
ValueStateManager& VM;
- ValueState* St;
+ const ValueState* St;
- FindUndefExpr(ValueStateManager& V, ValueState* S) : VM(V), St(S) {}
+ FindUndefExpr(ValueStateManager& V, const ValueState* S) : VM(V), St(S) {}
Expr* FindExpr(Expr* Ex) {
ExplodedNode<ValueState> *N = *(*I)->pred_begin();
ProgramPoint P = N->getLocation();
- ValueState* St = (*I)->getState();
+ const ValueState* St = (*I)->getState();
if (PostStmt* PS = dyn_cast<PostStmt>(&P))
if (PS->getStmt() == Ex)
ExplodedNode<ValueState>* Pred) {
ValueStateManager& StateMgr = Eng.getStateManager();
- ValueState* St = Builder.GetState(Pred);
+ const ValueState* St = Builder.GetState(Pred);
// Invalidate all arguments passed in by reference (LVals).
// We just invalidate all arguments passed in by references.
ValueStateManager& StateMgr = Eng.getStateManager();
- ValueState* St = Builder.GetState(Pred);
+ const ValueState* St = Builder.GetState(Pred);
for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
I != E; ++I) {
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
Expr* E, ExplodedNode<ValueState>* Pred,
- ValueState* St, RVal TargetLV, RVal Val) {
+ const ValueState* St, RVal TargetLV, RVal Val) {
// This code basically matches the "safety-net" logic of GRExprEngine:
// bind Val to TargetLV, and create a new node. We replicate it here
return T ? *T : NULL;
}
-ValueState*
-ValueStateManager::RemoveDeadBindings(ValueState* St, Stmt* Loc,
+const ValueState*
+ValueStateManager::RemoveDeadBindings(const ValueState* St, Stmt* Loc,
const LiveVariables& Liveness,
DeadSymbolsTy& DeadSymbols) {
for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I)
if (!Marked.count(I.getKey())) {
- NewSt.VarBindings = Remove(NewSt, I.getKey());
+ NewSt.St = StMgr->Remove(NewSt.St, lval::DeclVal(I.getKey()));
RVal X = I.getData();
return getPersistentState(NewSt);
}
-
-RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) {
+const ValueState* ValueStateManager::SetRVal(const ValueState* St, LVal LV,
+ RVal V) {
- if (isa<UnknownVal>(LV))
- return UnknownVal();
+ Store OldStore = St->getStore();
+ Store NewStore = StMgr->SetRVal(OldStore, LV, V);
- assert (!isa<UndefinedVal>(LV));
+ if (NewStore == OldStore)
+ return St;
- switch (LV.getSubKind()) {
- case lval::DeclValKind: {
- ValueState::VarBindingsTy::data_type* T =
- St->VarBindings.lookup(cast<lval::DeclVal>(LV).getDecl());
-
- return T ? *T : UnknownVal();
- }
-
- // FIXME: We should limit how far a "ContentsOf" will go...
-
- case lval::SymbolValKind: {
-
-
- // FIXME: This is a broken representation of memory, and is prone
- // to crashing the analyzer when addresses to symbolic values are
- // passed through casts. We need a better representation of symbolic
- // memory (or just memory in general); probably we should do this
- // as a plugin class (similar to GRTransferFuncs).
-
-#if 0
- const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
- assert (T.getTypePtr());
-
- // Punt on "symbolic" function pointers.
- if (T->isFunctionType())
- return UnknownVal();
+ ValueState NewSt = *St;
+ NewSt.St = NewStore;
+ return getPersistentState(NewSt);
+}
- if (T->isPointerType())
- return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
- else
- return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
-#endif
-
- return UnknownVal();
- }
-
- case lval::ConcreteIntKind:
- // Some clients may call GetRVal with such an option simply because
- // they are doing a quick scan through their LVals (potentially to
- // invalidate their bindings). Just return Undefined.
- return UndefinedVal();
-
- case lval::ArrayOffsetKind:
- case lval::FieldOffsetKind:
- return UnknownVal();
-
- case lval::FuncValKind:
- return LV;
-
- case lval::StringLiteralValKind:
- // FIXME: Implement better support for fetching characters from strings.
- return UnknownVal();
-
- default:
- assert (false && "Invalid LVal.");
- break;
- }
+const ValueState* ValueStateManager::Unbind(const ValueState* St, LVal LV) {
+ Store OldStore = St->getStore();
+ Store NewStore = StMgr->Remove(OldStore, LV);
- return UnknownVal();
+ if (NewStore == OldStore)
+ return St;
+
+ ValueState NewSt = *St;
+ NewSt.St = NewStore;
+ return getPersistentState(NewSt);
}
-ValueState* ValueStateManager::AddNE(ValueState* St, SymbolID sym,
- const llvm::APSInt& V) {
+
+const ValueState* ValueStateManager::AddNE(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V) {
// First, retrieve the NE-set associated with the given symbol.
ValueState::ConstNotEqTy::data_type* T = St->ConstNotEq.lookup(sym);
return getPersistentState(NewSt);
}
-ValueState* ValueStateManager::AddEQ(ValueState* St, SymbolID sym,
- const llvm::APSInt& V) {
+const ValueState* ValueStateManager::AddEQ(const ValueState* St, SymbolID sym,
+ const llvm::APSInt& V) {
// Create a new state with the old binding replaced.
ValueState NewSt = *St;
return getPersistentState(NewSt);
}
+const ValueState* ValueStateManager::getInitialState() {
-ValueState* ValueStateManager::SetRVal(ValueState* St, LVal LV, RVal V) {
-
- switch (LV.getSubKind()) {
-
- case lval::DeclValKind:
- return V.isUnknown()
- ? UnbindVar(St, cast<lval::DeclVal>(LV).getDecl())
- : BindVar(St, cast<lval::DeclVal>(LV).getDecl(), V);
-
- default:
- assert ("SetRVal for given LVal type not yet implemented.");
- return St;
- }
-}
-
-void ValueStateManager::BindVar(ValueState& StImpl, VarDecl* D, RVal V) {
- StImpl.VarBindings = VBFactory.Add(StImpl.VarBindings, D, V);
-}
-
-ValueState* ValueStateManager::BindVar(ValueState* St, VarDecl* D, RVal V) {
-
- // Create a new state with the old binding removed.
- ValueState NewSt = *St;
- NewSt.VarBindings = VBFactory.Add(NewSt.VarBindings, D, V);
-
- // Get the persistent copy.
- return getPersistentState(NewSt);
-}
-
-ValueState* ValueStateManager::UnbindVar(ValueState* St, VarDecl* D) {
-
- // Create a new state with the old binding removed.
- ValueState NewSt = *St;
- NewSt.VarBindings = VBFactory.Remove(NewSt.VarBindings, D);
-
- // Get the persistent copy.
- return getPersistentState(NewSt);
-}
-
-void ValueStateManager::Unbind(ValueState& StImpl, LVal LV) {
-
- if (isa<lval::DeclVal>(LV))
- StImpl.VarBindings = VBFactory.Remove(StImpl.VarBindings,
- cast<lval::DeclVal>(LV).getDecl());
-
-}
-
-ValueState* ValueStateManager::getInitialState() {
-
- // Create a state with empty variable bindings.
ValueState StateImpl(EnvMgr.getInitialEnvironment(),
- VBFactory.GetEmptyMap(),
+ StMgr->getInitialStore(),
CNEFactory.GetEmptyMap(),
CEFactory.GetEmptyMap());
return getPersistentState(StateImpl);
}
-ValueState* ValueStateManager::getPersistentState(ValueState& State) {
+const ValueState* ValueStateManager::getPersistentState(ValueState& State) {
llvm::FoldingSetNodeID ID;
State.Profile(ID);