diff options
-rw-r--r-- | Analysis/GRConstants.cpp | 735 | ||||
-rw-r--r-- | Analysis/RValues.cpp | 272 | ||||
-rw-r--r-- | Analysis/RValues.h | 393 | ||||
-rw-r--r-- | Analysis/ValueState.h | 162 |
4 files changed, 836 insertions, 726 deletions
diff --git a/Analysis/GRConstants.cpp b/Analysis/GRConstants.cpp index ae6cdf7bf9..2229e473ef 100644 --- a/Analysis/GRConstants.cpp +++ b/Analysis/GRConstants.cpp @@ -15,6 +15,9 @@ // //===----------------------------------------------------------------------===// +#include "RValues.h" +#include "ValueState.h" + #include "clang/Analysis/PathSensitive/GREngine.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" @@ -44,726 +47,6 @@ using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// -/// 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) {} - - bool isInitialized() const { return Data != (unsigned) ~0; } - operator unsigned() const { assert (isInitialized()); return Data; } -}; - -class VISIBILITY_HIDDEN ValueKey { - uintptr_t Raw; - 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; - } - - ValueKey(const ValueDecl* VD) - : Raw(reinterpret_cast<uintptr_t>(VD) | IsDecl) { - assert(VD && "ValueDecl cannot be NULL."); - } - - 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; } - bool isBlkExpr() const { return getKind() == IsBlkExpr; } - bool isDecl() const { return getKind() == IsDecl; } - 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()); - } - - inline bool operator==(const ValueKey& X) const { - return isSymbol() ? getSymbolID() == X.getSymbolID() - : getPtr() == X.getPtr(); - } - - 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 - -// Machinery to get cast<> and dyn_cast<> working with ValueKey. -namespace llvm { - template<> inline bool isa<ValueDecl,ValueKey>(const ValueKey& V) { - return V.getKind() == ValueKey::IsDecl; - } - template<> inline bool isa<Stmt,ValueKey>(const ValueKey& V) { - return ((unsigned) V.getKind()) < ValueKey::IsDecl; - } - template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,ValueKey> { - typedef const ValueDecl* ret_type; - }; - template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,ValueKey> { - typedef const Stmt* ret_type; - }; - template<> struct VISIBILITY_HIDDEN simplify_type<ValueKey> { - typedef void* SimpleType; - static inline SimpleType getSimplifiedValue(const ValueKey &V) { - return V.getPtr(); - } - }; -} // end llvm namespace - - -//===----------------------------------------------------------------------===// -// 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; -} - -//===----------------------------------------------------------------------===// -// ValueManager. -//===----------------------------------------------------------------------===// - -namespace { - -typedef llvm::ImmutableSet<APSInt > APSIntSetTy; - - -class VISIBILITY_HIDDEN ValueManager { - ASTContext& Ctx; - - typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<APSInt> > APSIntSetTy; - APSIntSetTy APSIntSet; - - llvm::BumpPtrAllocator BPAlloc; - -public: - ValueManager(ASTContext& ctx) : Ctx(ctx) {} - ~ValueManager(); - - 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()); -}; -} // 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); -} - -//===----------------------------------------------------------------------===// -// Expression Values. -//===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN RValue { -public: - enum BaseKind { LValueKind=0x0, NonLValueKind=0x1, - UninitializedKind=0x2, InvalidKind=0x3 }; - - enum { BaseBits = 2, BaseMask = 0x3 }; - -private: - void* Data; - unsigned Kind; - -protected: - RValue(const void* d, bool isLValue, unsigned ValKind) - : Data(const_cast<void*>(d)), - Kind((isLValue ? LValueKind : NonLValueKind) | (ValKind << BaseBits)) {} - - explicit RValue(BaseKind k) - : Data(0), Kind(k) {} - - void* getRawPtr() const { - return reinterpret_cast<void*>(Data); - } - -public: - ~RValue() {}; - - 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; } - - void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned) getRawKind()); - ID.AddPointer(reinterpret_cast<void*>(Data)); - } - - bool operator==(const RValue& RHS) const { - return getRawKind() == RHS.getRawKind() && Data == RHS.Data; - } - - static RValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D); - - inline bool isValid() const { return getRawKind() != InvalidKind; } - inline bool isInvalid() const { return getRawKind() == InvalidKind; } - - 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; } -}; - -class VISIBILITY_HIDDEN InvalidValue : public RValue { -public: - InvalidValue() : RValue(InvalidKind) {} - - static inline bool classof(const RValue* V) { - return V->getBaseKind() == InvalidKind; - } -}; - -class VISIBILITY_HIDDEN UninitializedValue : public RValue { -public: - UninitializedValue() : RValue(UninitializedKind) {} - - static inline bool classof(const RValue* V) { - return V->getBaseKind() == UninitializedKind; - } -}; - -class VISIBILITY_HIDDEN NonLValue : public RValue { -protected: - NonLValue(unsigned SubKind, const void* d) : RValue(d, false, SubKind) {} - -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; - - // 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 inline NonLValue GetIntTruthValue(ValueManager& ValMgr, bool X) { - return GetValue(ValMgr, X ? 1U : 0U, ValMgr.getContext().IntTy); - } - - // Implement isa<T> support. - static inline bool classof(const RValue* V) { - return V->getBaseKind() >= NonLValueKind; - } -}; - -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 - -//===----------------------------------------------------------------------===// -// LValues. -//===----------------------------------------------------------------------===// - -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 { -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; - } -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// 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 { -public: - 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()); - } - - // Implement isa<T> support. - static inline bool classof(const RValue* V) { - return V->getSubKind() == ConcreteIntKind; - } -}; - -} // 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); - default: - 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)); - -#define NONLVALUE_DISPATCH(Op)\ -switch (getSubKind()*NumNonLValueKind+RHS.getSubKind()){\ - NONLVALUE_DISPATCH_CASE(ConcreteInt,ConcreteInt,Op)\ - default:\ - if (getBaseKind() == UninitializedKind ||\ - RHS.getBaseKind() == UninitializedKind)\ - return cast<NonLValue>(UninitializedValue());\ - assert (!isValid() || !RHS.isValid() && "Missing case.");\ - break;\ -}\ -return cast<NonLValue>(InvalidValue()); - -NonLValue NonLValue::Add(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(Add) -} - -NonLValue NonLValue::Sub(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(Sub) -} - -NonLValue NonLValue::Mul(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(Mul) -} - -NonLValue NonLValue::Div(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(Div) -} - -NonLValue NonLValue::Rem(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(Rem) -} - -NonLValue NonLValue::EQ(ValueManager& ValMgr, const NonLValue& RHS) const { - NONLVALUE_DISPATCH(EQ) -} - -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); - } - } -} - - -//===----------------------------------------------------------------------===// -// Utility methods for constructing Non-LValues. -//===----------------------------------------------------------------------===// - -NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T, - SourceLocation Loc) { - - return ConcreteInt(ValMgr.getValue(X, T, Loc)); -} - -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)); -} - -//===----------------------------------------------------------------------===// -// 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(); - break; - - case SymbolicNonLValueKind: - Out << '$' << cast<SymbolicNonLValue>(this)->getSymbolID(); - break; - - default: - assert (false && "Pretty-printed not implemented for this NonLValue."); - 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()->getName(); - break; - - default: - assert (false && "Pretty-printed not implemented for this LValue."); - break; - } -} - -//===----------------------------------------------------------------------===// -// ValueMapTy - A ImmutableMap type Stmt*/Decl*/Symbols to RValues. -//===----------------------------------------------------------------------===// - -typedef llvm::ImmutableMap<ValueKey,RValue> ValueMapTy; - -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; - -//===----------------------------------------------------------------------===// // The Checker. // // FIXME: This checker logic should be eventually broken into two components. @@ -780,7 +63,7 @@ namespace { class VISIBILITY_HIDDEN GRConstants { public: - typedef ValueMapTy StateTy; + typedef ValueState StateTy; typedef GRStmtNodeBuilder<GRConstants> StmtNodeBuilder; typedef GRBranchNodeBuilder<GRConstants> BranchNodeBuilder; typedef ExplodedGraph<GRConstants> GraphTy; @@ -822,7 +105,7 @@ protected: StmtNodeBuilder* Builder; /// StateMgr - Object that manages the data for all created states. - ValueMapTy::Factory StateMgr; + StateTy::Factory StateMgr; /// ValueMgr - Object that manages the data for all created RValues. ValueManager ValMgr; @@ -1493,13 +776,13 @@ void GRConstants::Visit(Stmt* S, GRConstants::NodeTy* Pred, // "Assume" logic. //===----------------------------------------------------------------------===// -StateTy GRConstants::Assume(StateTy St, LValue Cond, bool Assumption, - bool& isFeasible) { +GRConstants::StateTy GRConstants::Assume(StateTy St, LValue Cond, bool Assumption, + bool& isFeasible) { return St; } -StateTy GRConstants::Assume(StateTy St, NonLValue Cond, bool Assumption, - bool& isFeasible) { +GRConstants::StateTy GRConstants::Assume(StateTy St, NonLValue Cond, bool Assumption, + bool& isFeasible) { switch (Cond.getSubKind()) { default: diff --git a/Analysis/RValues.cpp b/Analysis/RValues.cpp new file mode 100644 index 0000000000..4008e765e0 --- /dev/null +++ b/Analysis/RValues.cpp @@ -0,0 +1,272 @@ +//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines RValue, LValue, and NonLValue, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#include "RValues.h" + +using namespace clang; +using llvm::dyn_cast; +using llvm::cast; +using llvm::APSInt; + +//===----------------------------------------------------------------------===// +// SymbolManager. +//===----------------------------------------------------------------------===// + +SymbolID SymbolManager::getSymbol(ParmVarDecl* D) { + SymbolID& X = DataToSymbol[D]; + + if (!X.isInitialized()) { + X = SymbolToData.size(); + SymbolToData.push_back(D); + } + + return X; +} + +SymbolManager::SymbolManager() {} +SymbolManager::~SymbolManager() {} + +//===----------------------------------------------------------------------===// +// ValueManager. +//===----------------------------------------------------------------------===// + +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); +} + + +//===----------------------------------------------------------------------===// +// 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); + default: + 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)); + +#define NONLVALUE_DISPATCH(Op)\ +switch (getSubKind()*NumNonLValueKind+RHS.getSubKind()){\ +NONLVALUE_DISPATCH_CASE(ConcreteInt,ConcreteInt,Op)\ +default:\ +if (getBaseKind() == UninitializedKind ||\ +RHS.getBaseKind() == UninitializedKind)\ +return cast<NonLValue>(UninitializedValue());\ +assert (!isValid() || !RHS.isValid() && "Missing case.");\ +break;\ +}\ +return cast<NonLValue>(InvalidValue()); + +NonLValue NonLValue::Add(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(Add) +} + +NonLValue NonLValue::Sub(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(Sub) +} + +NonLValue NonLValue::Mul(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(Mul) +} + +NonLValue NonLValue::Div(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(Div) +} + +NonLValue NonLValue::Rem(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(Rem) +} + +NonLValue NonLValue::EQ(ValueManager& ValMgr, const NonLValue& RHS) const { + NONLVALUE_DISPATCH(EQ) +} + +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); + } + } +} + + +//===----------------------------------------------------------------------===// +// Utility methods for constructing Non-LValues. +//===----------------------------------------------------------------------===// + +NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T, + SourceLocation Loc) { + + return ConcreteInt(ValMgr.getValue(X, T, Loc)); +} + +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)); +} + +//===----------------------------------------------------------------------===// +// 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(); + break; + + case SymbolicNonLValueKind: + Out << '$' << cast<SymbolicNonLValue>(this)->getSymbolID(); + break; + + default: + assert (false && "Pretty-printed not implemented for this NonLValue."); + 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()->getName(); + break; + + default: + assert (false && "Pretty-printed not implemented for this LValue."); + break; + } +} diff --git a/Analysis/RValues.h b/Analysis/RValues.h new file mode 100644 index 0000000000..90446a2cc5 --- /dev/null +++ b/Analysis/RValues.h @@ -0,0 +1,393 @@ +//== RValues.h - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines RValue, LValue, and NonLValue, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H +#define LLVM_CLANG_ANALYSIS_RVALUE_H + +// FIXME: reduce the number of includes. + +#include "clang/Analysis/PathSensitive/GREngine.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.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" +# |