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"
#include "llvm/ADT/SmallPtrSet.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
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
216
//===----------------------------------------------------------------------===//
// 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 };
enum { BaseBits = 2, BaseMask = 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 << BaseBits)) {}
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 & BaseMask); }
unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
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;
static RValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D);
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);
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:
void print(std::ostream& Out) const;
// 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 { SymbolicLValueKind, LValueDeclKind, NumLValueKind };
class VISIBILITY_HIDDEN SymbolicLValue : public LValue {
public:
SymbolicLValue(unsigned SymID)
: LValue(SymbolicLValueKind, 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() == SymbolicLValueKind;
}
};
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)
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
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())));
}
RValue RValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
QualType T = D->getType();
if (T->isPointerType() || T->isReferenceType())
return SymbolicLValue(SymMgr.getSymbol(D));
else
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:
cast<LValue>(this)->print(Out);
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 << '$' << cast<SymbolicNonLValue>(this)->getSymbolID();
break;
Ted Kremenek
committed
default:
assert (false && "Pretty-printed not implemented for this NonLValue.");
Ted Kremenek
committed
break;
}
}
void LValue::print(std::ostream& Out) const {
switch (getSubKind()) {
case SymbolicLValueKind:
Out << '$' << cast<SymbolicLValue>(this)->getSymbolID();
break;
case LValueDeclKind:
Out << cast<LValueDecl>(this)->getDecl()->getIdentifier();
break;
default:
assert (false && "Pretty-printed not implemented for this LValue.");
break;
}
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// 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));
}
};
}
typedef ValueMapTy StateTy;
//===----------------------------------------------------------------------===//
//
// FIXME: This checker logic should be eventually broken into two components.
// The first is the "meta"-level checking logic; the code that
// does the Stmt visitation, fetching values from the map, etc.
// The second part does the actual state manipulation. This way we
// get more of a separate of concerns of these two pieces, with the
// latter potentially being refactored back into the main checking
// logic.
//===----------------------------------------------------------------------===//
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->isSink()); Impl.push_back(N); }
Ted Kremenek
committed
void Add(NodeTy* N) { if (N && !N->isSink()) Impl.push_back(N); }
Ted Kremenek
committed
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;
/// UninitBranches - Nodes in the ExplodedGraph that result from
/// taking a branch based on an uninitialized value.
typedef llvm::SmallPtrSet<NodeTy*,5> UninitBranchesTy;
UninitBranchesTy UninitBranches;
Ted Kremenek
committed
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)
St = SetValue(St, LValueDecl(*I), RValue::GetSymbolValue(SymMgr, *I));
bool isUninitControlFlow(const NodeTy* N) const {
return N->isSink() && UninitBranches.count(const_cast<NodeTy*>(N)) != 0;
}
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);
/// Assume - Create new state by assuming that a given expression
/// is true or false.
inline StateTy Assume(StateTy St, RValue Cond, bool Assumption,
bool& isFeasible) {
if (isa<LValue>(Cond))
return Assume(St, cast<LValue>(Cond), Assumption, isFeasible);
else
return Assume(St, cast<NonLValue>(Cond), Assumption, isFeasible);
}
StateTy Assume(StateTy St, LValue Cond, bool Assumption, bool& isFeasible);
StateTy Assume(StateTy St, NonLValue Cond, bool Assumption, bool& isFeasible);
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::ProcessBranch(Stmt* Condition, Stmt* Term,
BranchNodeBuilder& builder) {
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
StateTy PrevState = builder.getState();
// Remove old bindings for subexpressions.
for (StateTy::iterator I=PrevState.begin(), E=PrevState.end(); I!=E; ++I)
if (I.getKey().isSubExpr())
PrevState = StateMgr.Remove(PrevState, I.getKey());
RValue V = GetValue(PrevState, Condition);
switch (V.getBaseKind()) {
default:
break;
case RValue::InvalidKind:
builder.generateNode(PrevState, true);
builder.generateNode(PrevState, false);
return;
case RValue::UninitializedKind: {
NodeTy* N = builder.generateNode(PrevState, true);
if (N) {
N->markAsSink();
UninitBranches.insert(N);
}
builder.markInfeasible(false);
return;
}
}
// Process the true branch.
bool isFeasible = true;
StateTy St = Assume(PrevState, V, true, isFeasible);
if (isFeasible) builder.generateNode(St, true);
else {
builder.markInfeasible(true);
isFeasible = true;
}
// Process the false branch.
St = Assume(PrevState, V, false, isFeasible);
if (isFeasible) builder.generateNode(St, false);
else builder.markInfeasible(false);
}
void GRConstants::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
Builder = &builder;
Ted Kremenek
committed
StmtEntryNode = builder.getLastNode();
CurrentStmt = S;
NodeSet Dst;