Newer
Older
//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- C++ -*-==//
//
Ted Kremenek
committed
// The LLValM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Constant Propagation via Graph Reachability
//
// This files defines a simple analysis that performs path-sensitive
// constant propagation within a function. An example use of this analysis
// is to perform simple checks for NULL dereferences.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GREngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallVector.h"
Ted Kremenek
committed
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
Ted Kremenek
committed
#include "llvm/Support/Streams.h"
#include <functional>
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#include <sstream>
#endif
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
/// ValueKey - A variant smart pointer that wraps either a ValueDecl* or a
/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
//===----------------------------------------------------------------------===//
namespace {
class SymbolID {
unsigned Data;
public:
SymbolID() : Data(~0) {}
SymbolID(unsigned x) : Data(x) {}
Ted Kremenek
committed
bool isInitialized() const { return Data != (unsigned) ~0; }
operator unsigned() const { assert (isInitialized()); return Data; }
};
Ted Kremenek
committed
class VISIBILITY_HIDDEN ValueKey {
void operator=(const ValueKey& RHS); // Do not implement.
public:
enum Kind { IsSubExpr=0x0, IsBlkExpr=0x1, IsDecl=0x2, // L-Value Bindings.
IsSymbol=0x3, // Symbol Bindings.
Flags=0x3 };
inline Kind getKind() const {
return (Kind) (Raw & Flags);
}
inline void* getPtr() const {
assert (getKind() != IsSymbol);
return reinterpret_cast<void*>(Raw & ~Flags);
}
inline SymbolID getSymbolID() const {
assert (getKind() == IsSymbol);
return Raw >> 2;
Ted Kremenek
committed
ValueKey(const ValueDecl* VD)
: Raw(reinterpret_cast<uintptr_t>(VD) | IsDecl) {
assert(VD && "ValueDecl cannot be NULL.");
}
Ted Kremenek
committed
ValueKey(Stmt* S, bool isBlkExpr = false)
: Raw(reinterpret_cast<uintptr_t>(S) | (isBlkExpr ? IsBlkExpr : IsSubExpr)){
assert(S && "Tracked statement cannot be NULL.");
ValueKey(SymbolID V)
: Raw((V << 2) | IsSymbol) {}
bool isSymbol() const { return getKind() == IsSymbol; }
bool isSubExpr() const { return getKind() == IsSubExpr; }
Ted Kremenek
committed
bool isBlkExpr() const { return getKind() == IsBlkExpr; }
bool isDecl() const { return getKind() == IsDecl; }
Ted Kremenek
committed
bool isStmt() const { return getKind() <= IsBlkExpr; }
inline void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger(isSymbol() ? 1 : 0);
if (isSymbol())
ID.AddInteger(getSymbolID());
else
ID.AddPointer(getPtr());
Ted Kremenek
committed
}
inline bool operator==(const ValueKey& X) const {
return isSymbol() ? getSymbolID() == X.getSymbolID()
: getPtr() == X.getPtr();
Ted Kremenek
committed
}
inline bool operator!=(const ValueKey& X) const {
return !operator==(X);
}
inline bool operator<(const ValueKey& X) const {
if (isSymbol())
return X.isSymbol() ? getSymbolID() < X.getSymbolID() : false;
return getPtr() < X.getPtr();
};
} // end anonymous namespace
Ted Kremenek
committed
// Machinery to get cast<> and dyn_cast<> working with ValueKey.
namespace llvm {
Ted Kremenek
committed
template<> inline bool isa<ValueDecl,ValueKey>(const ValueKey& V) {
return V.getKind() == ValueKey::IsDecl;
Ted Kremenek
committed
template<> inline bool isa<Stmt,ValueKey>(const ValueKey& V) {
return ((unsigned) V.getKind()) < ValueKey::IsDecl;
Ted Kremenek
committed
template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,ValueKey> {
typedef const ValueDecl* ret_type;
Ted Kremenek
committed
template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,ValueKey> {
typedef const Stmt* ret_type;
};
Ted Kremenek
committed
template<> struct VISIBILITY_HIDDEN simplify_type<ValueKey> {
typedef void* SimpleType;
Ted Kremenek
committed
static inline SimpleType getSimplifiedValue(const ValueKey &V) {
return V.getPtr();
}
};
} // end llvm namespace
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//===----------------------------------------------------------------------===//
// SymbolManager.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN SymbolData {
uintptr_t Data;
public:
enum Kind { ParmKind = 0x0, Mask = 0x3 };
SymbolData(ParmVarDecl* D)
: Data(reinterpret_cast<uintptr_t>(D) | ParmKind) {}
inline Kind getKind() const { return (Kind) (Data & Mask); }
inline void* getPtr() const { return reinterpret_cast<void*>(Data & ~Mask); }
inline bool operator==(const SymbolData& R) const { return Data == R.Data; }
};
}
// Machinery to get cast<> and dyn_cast<> working with SymbolData.
namespace llvm {
template<> inline bool isa<ParmVarDecl,SymbolData>(const SymbolData& V) {
return V.getKind() == SymbolData::ParmKind;
}
template<> struct VISIBILITY_HIDDEN cast_retty_impl<ParmVarDecl,SymbolData> {
typedef const ParmVarDecl* ret_type;
};
template<> struct VISIBILITY_HIDDEN simplify_type<SymbolData> {
typedef void* SimpleType;
static inline SimpleType getSimplifiedValue(const SymbolData &V) {
return V.getPtr();
}
};
} // end llvm namespace
namespace {
class VISIBILITY_HIDDEN SymbolManager {
std::vector<SymbolData> SymbolToData;
typedef llvm::DenseMap<void*,SymbolID> MapTy;
MapTy DataToSymbol;
public:
SymbolData getSymbolData(SymbolID id) const {
assert (id < SymbolToData.size());
return SymbolToData[id];
}
SymbolID getSymbol(ParmVarDecl* D);
};
} // end anonymous namespace
SymbolID SymbolManager::getSymbol(ParmVarDecl* D) {
SymbolID& X = DataToSymbol[D];
if (!X.isInitialized()) {
X = SymbolToData.size();
SymbolToData.push_back(D);
}
return X;
}
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
// ValueManager.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
namespace {
typedef llvm::ImmutableSet<APSInt > APSIntSetTy;
Ted Kremenek
committed
class VISIBILITY_HIDDEN ValueManager {
ASTContext& Ctx;
Ted Kremenek
committed
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<APSInt> > APSIntSetTy;
APSIntSetTy APSIntSet;
llvm::BumpPtrAllocator BPAlloc;
Ted Kremenek
committed
public:
ValueManager(ASTContext& ctx) : Ctx(ctx) {}
Ted Kremenek
committed
ASTContext& getContext() const { return Ctx; }
APSInt& getValue(const APSInt& X);
APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
APSInt& getValue(uint64_t X, QualType T,
SourceLocation Loc = SourceLocation());
Ted Kremenek
committed
};
} // end anonymous namespace
ValueManager::~ValueManager() {
// Note that the dstor for the contents of APSIntSet will never be called,
// so we iterate over the set and invoke the dstor for each APSInt. This
// frees an aux. memory allocated to represent very large constants.
for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I)
I->getValue().~APSInt();
}
APSInt& ValueManager::getValue(const APSInt& X) {
llvm::FoldingSetNodeID ID;
void* InsertPos;
typedef llvm::FoldingSetNodeWrapper<APSInt> FoldNodeTy;
X.Profile(ID);
FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(X);
APSIntSet.InsertNode(P, InsertPos);
}
return *P;
APSInt& ValueManager::getValue(uint64_t X, unsigned BitWidth, bool isUnsigned) {
APSInt V(BitWidth, isUnsigned);
V = X;
return getValue(V);
}
APSInt& ValueManager::getValue(uint64_t X, QualType T, SourceLocation Loc) {
unsigned bits = Ctx.getTypeSize(T, Loc);
APSInt V(bits, T->isUnsignedIntegerType());
V = X;
return getValue(V);
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Expression Values.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
namespace {
class VISIBILITY_HIDDEN RValue {
Ted Kremenek
committed
public:
enum BaseKind { LValueKind=0x0, NonLValueKind=0x1,
UninitializedKind=0x2, InvalidKind=0x3, BaseFlags = 0x3 };
Ted Kremenek
committed
private:
void* Data;
unsigned Kind;
Ted Kremenek
committed
protected:
RValue(const void* d, bool isLValue, unsigned ValKind)
: Data(const_cast<void*>(d)),
Kind((isLValue ? LValueKind : NonLValueKind) | (ValKind << 2)) {}
Ted Kremenek
committed
explicit RValue(BaseKind k)
: Data(0), Kind(k) {}
void* getRawPtr() const {
return reinterpret_cast<void*>(Data);
}
Ted Kremenek
committed
public:
Ted Kremenek
committed
RValue Cast(ValueManager& ValMgr, Expr* CastExpr) const;
unsigned getRawKind() const { return Kind; }
BaseKind getBaseKind() const { return (BaseKind) (Kind & 0x3); }
unsigned getSubKind() const { return (Kind & ~0x3) >> 2; }
Ted Kremenek
committed
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned) getRawKind());
ID.AddPointer(reinterpret_cast<void*>(Data));
Ted Kremenek
committed
}
bool operator==(const RValue& RHS) const {
return getRawKind() == RHS.getRawKind() && Data == RHS.Data;
Ted Kremenek
committed
inline bool isValid() const { return getRawKind() != InvalidKind; }
inline bool isInvalid() const { return getRawKind() == InvalidKind; }
Ted Kremenek
committed
void print(std::ostream& OS) const;
void print() const { print(*llvm::cerr.stream()); }
// Implement isa<T> support.
static inline bool classof(const RValue*) { return true; }
Ted Kremenek
committed
};
class VISIBILITY_HIDDEN InvalidValue : public RValue {
Ted Kremenek
committed
public:
InvalidValue() : RValue(InvalidKind) {}
Ted Kremenek
committed
static inline bool classof(const RValue* V) {
return V->getBaseKind() == InvalidKind;
Ted Kremenek
committed
}
class VISIBILITY_HIDDEN UninitializedValue : public RValue {
public:
UninitializedValue() : RValue(UninitializedKind) {}
static inline bool classof(const RValue* V) {
return V->getBaseKind() == UninitializedKind;
}
};
Ted Kremenek
committed
class VISIBILITY_HIDDEN NonLValue : public RValue {
Ted Kremenek
committed
protected:
NonLValue(unsigned SubKind, const void* d) : RValue(d, false, SubKind) {}
Ted Kremenek
committed
public:
void print(std::ostream& Out) const;
// Arithmetic operators.
NonLValue Add(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue Sub(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue Mul(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue Div(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue Rem(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const;
Ted Kremenek
committed
// Equality operators.
NonLValue EQ(ValueManager& ValMgr, const NonLValue& RHS) const;
NonLValue NE(ValueManager& ValMgr, const NonLValue& RHS) const;
// Utility methods to create NonLValues.
static NonLValue GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
SourceLocation Loc = SourceLocation());
static NonLValue GetValue(ValueManager& ValMgr, IntegerLiteral* I);
static NonLValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D);
Ted Kremenek
committed
static inline NonLValue GetIntTruthValue(ValueManager& ValMgr, bool X) {
return GetValue(ValMgr, X ? 1U : 0U, ValMgr.getContext().IntTy);
}
Ted Kremenek
committed
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getBaseKind() >= NonLValueKind;
Ted Kremenek
committed
}
};
class VISIBILITY_HIDDEN LValue : public RValue {
protected:
LValue(unsigned SubKind, void* D) : RValue(D, true, SubKind) {}
public:
// Equality operators.
NonLValue EQ(ValueManager& ValMgr, const LValue& RHS) const;
NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const;
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getBaseKind() == LValueKind;
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
namespace {
enum { LValueDeclKind, NumLValueKind };
class VISIBILITY_HIDDEN LValueDecl : public LValue {
Ted Kremenek
committed
public:
LValueDecl(const ValueDecl* vd)
: LValue(LValueDeclKind,const_cast<ValueDecl*>(vd)) {}
ValueDecl* getDecl() const {
return static_cast<ValueDecl*>(getRawPtr());
inline bool operator==(const LValueDecl& R) const {
return getDecl() == R.getDecl();
}
inline bool operator!=(const LValueDecl& R) const {
return getDecl() != R.getDecl();
}
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getSubKind() == LValueDeclKind;
//===----------------------------------------------------------------------===//
// Non-LValues.
//===----------------------------------------------------------------------===//
namespace {
enum { SymbolicNonLValueKind, ConcreteIntKind, ConstrainedIntegerKind,
NumNonLValueKind };
class VISIBILITY_HIDDEN SymbolicNonLValue : public NonLValue {
public:
SymbolicNonLValue(unsigned SymID)
: NonLValue(SymbolicNonLValueKind,
reinterpret_cast<void*>((uintptr_t) SymID)) {}
SymbolID getSymbolID() const {
return (SymbolID) reinterpret_cast<uintptr_t>(getRawPtr());
}
static inline bool classof(const RValue* V) {
return V->getSubKind() == SymbolicNonLValueKind;
}
};
class VISIBILITY_HIDDEN ConcreteInt : public NonLValue {
ConcreteInt(const APSInt& V) : NonLValue(ConcreteIntKind, &V) {}
const APSInt& getValue() const {
return *static_cast<APSInt*>(getRawPtr());
}
// Arithmetic operators.
ConcreteInt Add(ValueManager& ValMgr, const ConcreteInt& V) const {
return ValMgr.getValue(getValue() + V.getValue());
}
ConcreteInt Sub(ValueManager& ValMgr, const ConcreteInt& V) const {
return ValMgr.getValue(getValue() - V.getValue());
ConcreteInt Mul(ValueManager& ValMgr, const ConcreteInt& V) const {
return ValMgr.getValue(getValue() * V.getValue());
}
ConcreteInt Div(ValueManager& ValMgr, const ConcreteInt& V) const {
return ValMgr.getValue(getValue() / V.getValue());
}
ConcreteInt Rem(ValueManager& ValMgr, const ConcreteInt& V) const {
return ValMgr.getValue(getValue() % V.getValue());
}
ConcreteInt UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const {
assert (U->getType() == U->getSubExpr()->getType());
assert (U->getType()->isIntegerType());
return ValMgr.getValue(-getValue());
}
// Casting.
ConcreteInt Cast(ValueManager& ValMgr, Expr* CastExpr) const {
assert (CastExpr->getType()->isIntegerType());
APSInt X(getValue());
X.extOrTrunc(ValMgr.getContext().getTypeSize(CastExpr->getType(),
CastExpr->getLocStart()));
return ValMgr.getValue(X);
}
// Equality operators.
ConcreteInt EQ(ValueManager& ValMgr, const ConcreteInt& V) const {
const APSInt& Val = getValue();
return ValMgr.getValue(Val == V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
}
ConcreteInt NE(ValueManager& ValMgr, const ConcreteInt& V) const {
const APSInt& Val = getValue();
return ValMgr.getValue(Val != V.getValue() ? 1U : 0U,
Val.getBitWidth(), Val.isUnsigned());
Ted Kremenek
committed
// Implement isa<T> support.
static inline bool classof(const RValue* V) {
return V->getSubKind() == ConcreteIntKind;
Ted Kremenek
committed
};
Ted Kremenek
committed
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-LValues.
//===----------------------------------------------------------------------===//
RValue RValue::Cast(ValueManager& ValMgr, Expr* CastExpr) const {
switch (getSubKind()) {
case ConcreteIntKind:
return cast<ConcreteInt>(this)->Cast(ValMgr, CastExpr);
default:
return InvalidValue();
}
}
NonLValue NonLValue::UnaryMinus(ValueManager& ValMgr, UnaryOperator* U) const {
switch (getSubKind()) {
case ConcreteIntKind:
return cast<ConcreteInt>(this)->UnaryMinus(ValMgr, U);
return cast<NonLValue>(InvalidValue());
#define NONLVALUE_DISPATCH_CASE(k1,k2,Op)\
case (k1##Kind*NumNonLValueKind+k2##Kind):\
return cast<k1>(*this).Op(ValMgr,cast<k2>(RHS));
Ted Kremenek
committed
#define NONLVALUE_DISPATCH(Op)\
switch (getSubKind()*NumNonLValueKind+RHS.getSubKind()){\
NONLVALUE_DISPATCH_CASE(ConcreteInt,ConcreteInt,Op)\
Ted Kremenek
committed
default:\
if (getBaseKind() == UninitializedKind ||\
RHS.getBaseKind() == UninitializedKind)\
return cast<NonLValue>(UninitializedValue());\
Ted Kremenek
committed
assert (!isValid() || !RHS.isValid() && "Missing case.");\
break;\
}\
return cast<NonLValue>(InvalidValue());
Ted Kremenek
committed
NonLValue NonLValue::Add(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(Add)
Ted Kremenek
committed
}
NonLValue NonLValue::Sub(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(Sub)
Ted Kremenek
committed
}
NonLValue NonLValue::Mul(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(Mul)
NonLValue NonLValue::Div(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(Div)
Ted Kremenek
committed
}
NonLValue NonLValue::Rem(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(Rem)
}
NonLValue NonLValue::EQ(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(EQ)
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
NonLValue NonLValue::NE(ValueManager& ValMgr, const NonLValue& RHS) const {
NONLVALUE_DISPATCH(NE)
}
#undef NONLVALUE_DISPATCH_CASE
#undef NONLVALUE_DISPATCH
//===----------------------------------------------------------------------===//
// Transfer function dispatch for LValues.
//===----------------------------------------------------------------------===//
NonLValue LValue::EQ(ValueManager& ValMgr, const LValue& RHS) const {
if (getSubKind() != RHS.getSubKind())
return NonLValue::GetIntTruthValue(ValMgr, false);
switch (getSubKind()) {
default:
assert(false && "EQ not implemented for this LValue.");
return cast<NonLValue>(InvalidValue());
case LValueDeclKind: {
bool b = cast<LValueDecl>(*this) == cast<LValueDecl>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
}
}
NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
if (getSubKind() != RHS.getSubKind())
return NonLValue::GetIntTruthValue(ValMgr, true);
switch (getSubKind()) {
default:
assert(false && "EQ not implemented for this LValue.");
return cast<NonLValue>(InvalidValue());
case LValueDeclKind: {
bool b = cast<LValueDecl>(*this) != cast<LValueDecl>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
}
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Utility methods for constructing Non-LValues.
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
SourceLocation Loc) {
return ConcreteInt(ValMgr.getValue(X, T, Loc));
Ted Kremenek
committed
NonLValue NonLValue::GetValue(ValueManager& ValMgr, IntegerLiteral* I) {
return ConcreteInt(ValMgr.getValue(APSInt(I->getValue(),
I->getType()->isUnsignedIntegerType())));
}
NonLValue NonLValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
return SymbolicNonLValue(SymMgr.getSymbol(D));
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//
void RValue::print(std::ostream& Out) const {
switch (getBaseKind()) {
case InvalidKind:
Out << "Invalid";
break;
case NonLValueKind:
cast<NonLValue>(this)->print(Out);
break;
case LValueKind:
assert (false && "FIXME: LValue printing not implemented.");
break;
case UninitializedKind:
Out << "Uninitialized";
break;
default:
assert (false && "Invalid RValue.");
}
}
void NonLValue::print(std::ostream& Out) const {
switch (getSubKind()) {
case ConcreteIntKind:
Out << cast<ConcreteInt>(this)->getValue().toString();
Ted Kremenek
committed
break;
case SymbolicNonLValueKind:
Out << "sym-" << cast<SymbolicNonLValue>(this)->getSymbolID();
break;
Ted Kremenek
committed
default:
assert (false && "Pretty-printed not implemented for this NonLValue.");
Ted Kremenek
committed
break;
}
}
//===----------------------------------------------------------------------===//
// ValueMapTy - A ImmutableMap type Stmt*/Decl*/Symbols to RValues.
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
typedef llvm::ImmutableMap<ValueKey,RValue> ValueMapTy;
Ted Kremenek
committed
namespace clang {
template<>
struct VISIBILITY_HIDDEN GRTrait<ValueMapTy> {
static inline void* toPtr(ValueMapTy M) {
return reinterpret_cast<void*>(M.getRoot());
}
static inline ValueMapTy toState(void* P) {
return ValueMapTy(static_cast<ValueMapTy::TreeTy*>(P));
}
};
}
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
namespace {
Ted Kremenek
committed
class VISIBILITY_HIDDEN GRConstants {
public:
Ted Kremenek
committed
typedef ValueMapTy StateTy;
typedef GRStmtNodeBuilder<GRConstants> StmtNodeBuilder;
typedef GRBranchNodeBuilder<GRConstants> BranchNodeBuilder;
typedef ExplodedGraph<GRConstants> GraphTy;
typedef GraphTy::NodeTy NodeTy;
Ted Kremenek
committed
class NodeSet {
typedef llvm::SmallVector<NodeTy*,3> ImplTy;
ImplTy Impl;
public:
NodeSet() {}
NodeSet(NodeTy* N) { assert (N && !N->isInfeasible()); Impl.push_back(N); }
void Add(NodeTy* N) { if (N && !N->isInfeasible()) Impl.push_back(N); }
typedef ImplTy::iterator iterator;
typedef ImplTy::const_iterator const_iterator;
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
Ted Kremenek
committed
iterator begin() { return Impl.begin(); }
iterator end() { return Impl.end(); }
const_iterator begin() const { return Impl.begin(); }
const_iterator end() const { return Impl.end(); }
};
protected:
/// G - the simulation graph.
GraphTy& G;
Ted Kremenek
committed
/// Liveness - live-variables information the ValueDecl* and block-level
/// Expr* in the CFG. Used to prune out dead state.
Ted Kremenek
committed
LiveVariables Liveness;
/// Builder - The current GRStmtNodeBuilder which is used when building the nodes
Ted Kremenek
committed
/// for a given statement.
StmtNodeBuilder* Builder;
Ted Kremenek
committed
/// StateMgr - Object that manages the data for all created states.
ValueMapTy::Factory StateMgr;
/// ValueMgr - Object that manages the data for all created RValues.
Ted Kremenek
committed
ValueManager ValMgr;
/// SymMgr - Object that manages the symbol information.
SymbolManager SymMgr;
Ted Kremenek
committed
/// StmtEntryNode - The immediate predecessor node.
NodeTy* StmtEntryNode;
/// CurrentStmt - The current block-level statement.
Stmt* CurrentStmt;
bool StateCleaned;
ASTContext& getContext() const { return G.getContext(); }
public:
Ted Kremenek
committed
GRConstants(GraphTy& g) : G(g), Liveness(G.getCFG(), G.getFunctionDecl()),
Builder(NULL), ValMgr(G.getContext()), StmtEntryNode(NULL),
CurrentStmt(NULL) {
// Compute liveness information.
Ted Kremenek
committed
Liveness.runOnCFG(G.getCFG());
Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
/// getCFG - Returns the CFG associated with this analysis.
CFG& getCFG() { return G.getCFG(); }
Ted Kremenek
committed
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
StateTy getInitialState() {
StateTy St = StateMgr.GetEmptyMap();
// Iterate the parameters.
FunctionDecl& F = G.getFunctionDecl();
for (FunctionDecl::param_iterator I=F.param_begin(), E=F.param_end();
I!=E; ++I) {
// For now we only support symbolic values for non-pointer types.
if ((*I)->getType()->isPointerType() ||
(*I)->getType()->isReferenceType())
continue;
// FIXME: Set these values to a symbol, not Uninitialized.
St = SetValue(St, LValueDecl(*I), NonLValue::GetSymbolValue(SymMgr, *I));
}
Ted Kremenek
committed
/// ProcessStmt - Called by GREngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);
/// ProcessBranch - Called by GREngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder)
{}
Ted Kremenek
committed
/// RemoveDeadBindings - Return a new state that is the same as 'M' except
/// that all subexpression mappings are removed and that any
/// block-level expressions that are not live at 'S' also have their
/// mappings removed.
StateTy RemoveDeadBindings(Stmt* S, StateTy M);
StateTy SetValue(StateTy St, Stmt* S, const RValue& V);
Ted Kremenek
committed
StateTy SetValue(StateTy St, const Stmt* S, const RValue& V) {
return SetValue(St, const_cast<Stmt*>(S), V);
}
StateTy SetValue(StateTy St, const LValue& LV, const RValue& V);
RValue GetValue(const StateTy& St, Stmt* S);
inline RValue GetValue(const StateTy& St, const Stmt* S) {
return GetValue(St, const_cast<Stmt*>(S));
}
RValue GetValue(const StateTy& St, const LValue& LV);
Ted Kremenek
committed
LValue GetLValue(const StateTy& St, Stmt* S);
Ted Kremenek
committed
void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
Ted Kremenek
committed
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst);
Ted Kremenek
committed
/// VisitUnaryOperator - Transfer function logic for unary operators.
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
Ted Kremenek
committed
/// VisitBinaryOperator - Transfer function logic for binary operators.
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
};
} // end anonymous namespace
Ted Kremenek
committed
void GRConstants::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
Builder = &builder;
Ted Kremenek
committed
StmtEntryNode = builder.getLastNode();
CurrentStmt = S;
NodeSet Dst;
StateCleaned = false;
Visit(S, StmtEntryNode, Dst);
// If no nodes were generated, generate a new node that has all the
// dead mappings removed.
if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) {
StateTy St = RemoveDeadBindings(S, StmtEntryNode->getState());
builder.generateNode(S, St, StmtEntryNode);
}
Ted Kremenek
committed
CurrentStmt = NULL;
StmtEntryNode = NULL;
Builder = NULL;
RValue GRConstants::GetValue(const StateTy& St, const LValue& LV) {
switch (LV.getSubKind()) {
case LValueDeclKind: {
Ted Kremenek
committed
StateTy::TreeTy* T = St.SlimFind(cast<LValueDecl>(LV).getDecl());
return T ? T->getValue().second : InvalidValue();
}
default:
assert (false && "Invalid LValue.");
break;
}
Ted Kremenek
committed
return InvalidValue();
}
RValue GRConstants::GetValue(const StateTy& St, Stmt* S) {
for (;;) {
switch (S->getStmtClass()) {
// ParenExprs are no-ops.
case Stmt::ParenExprClass:
S = cast<ParenExpr>(S)->getSubExpr();
continue;
// DeclRefExprs can either evaluate to an LValue or a Non-LValue
// (assuming an implicit "load") depending on the context. In this
// context we assume that we are retrieving the value contained
// within the referenced variables.
case Stmt::DeclRefExprClass:
return GetValue(St, LValueDecl(cast<DeclRefExpr>(S)->getDecl()));
// Integer literals evaluate to an RValue. Simply retrieve the
// RValue for the literal.
case Stmt::IntegerLiteralClass:
return NonLValue::GetValue(ValMgr, cast<IntegerLiteral>(S));
// Casts where the source and target type are the same
// are no-ops. We blast through these to get the descendant
// subexpression that has a value.
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr* C = cast<ImplicitCastExpr>(S);
if (C->getType() == C->getSubExpr()->getType()) {
S = C->getSubExpr();
continue;
}
break;
}
case Stmt::CastExprClass: {
CastExpr* C = cast<CastExpr>(S);
if (C->getType() == C->getSubExpr()->getType()) {
S = C->getSubExpr();
continue;
}
break;
}
// Handle all other Stmt* using a lookup.
default:
break;
};
break;
}
StateTy::TreeTy* T = St.SlimFind(S);
Ted Kremenek
committed
return T ? T->getValue().second : InvalidValue();
Ted Kremenek
committed
LValue GRConstants::GetLValue(const StateTy& St, Stmt* S) {
while (ParenExpr* P = dyn_cast<ParenExpr>(S))
S = P->getSubExpr();
Ted Kremenek
committed
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S))
return LValueDecl(DR->getDecl());
return cast<LValue>(GetValue(St, S));
Ted Kremenek
committed
GRConstants::StateTy GRConstants::SetValue(StateTy St, Stmt* S,
assert (S);
Ted Kremenek
committed
if (!StateCleaned) {
St = RemoveDeadBindings(CurrentStmt, St);
StateCleaned = true;
}
bool isBlkExpr = false;
if (S == CurrentStmt) {
isBlkExpr = getCFG().isBlkExpr(S);