From 10246e8bfa23867d2e794204c9817c1183a13277 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 29 Apr 2008 23:24:44 +0000 Subject: [PATCH] Add lval::ArrayOffset, which represent the locations of entries in an array. llvm-svn: 50453 --- .../PathSensitive/BasicValueFactory.h | 6 +- .../clang/Analysis/PathSensitive/RValues.h | 50 ++++++++++- clang/lib/Analysis/BasicValueFactory.cpp | 39 ++++++++ clang/lib/Analysis/GRExprEngine.cpp | 90 ++++++------------- clang/lib/Analysis/RValues.cpp | 9 ++ clang/lib/Analysis/ValueState.cpp | 1 + 6 files changed, 127 insertions(+), 68 deletions(-) diff --git a/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h index e36e521d796e..c3729ed53e2a 100644 --- a/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -43,10 +43,11 @@ class BasicValueFactory { APSIntSetTy APSIntSet; SymIntCSetTy SymIntCSet; void* PersistentRVals; + void* PersistentRValPairs; public: BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) - : Ctx(ctx), BPAlloc(Alloc), PersistentRVals(0) {} + : Ctx(ctx), BPAlloc(Alloc), PersistentRVals(0), PersistentRValPairs(0) {} ~BasicValueFactory(); @@ -73,6 +74,9 @@ public: const std::pair& getPersistentRValWithData(const RVal& V, uintptr_t Data); + + const std::pair& + getPersistentRValPair(const RVal& V1, const RVal& V2); }; } // end clang namespace diff --git a/clang/include/clang/Analysis/PathSensitive/RValues.h b/clang/include/clang/Analysis/PathSensitive/RValues.h index 353046d4be06..9db6850be68e 100644 --- a/clang/include/clang/Analysis/PathSensitive/RValues.h +++ b/clang/include/clang/Analysis/PathSensitive/RValues.h @@ -279,7 +279,8 @@ public: namespace lval { enum Kind { SymbolValKind, GotoLabelKind, DeclValKind, FuncValKind, - ConcreteIntKind, StringLiteralValKind, FieldOffsetKind }; + ConcreteIntKind, StringLiteralValKind, FieldOffsetKind, + ArrayOffsetKind }; class SymbolVal : public LVal { public: @@ -415,9 +416,7 @@ public: class FieldOffset : public LVal { FieldOffset(const std::pair& data) - : LVal(FieldOffsetKind, &data) { - assert (isa(data.first)); - } + : LVal(FieldOffsetKind, &data) {} public: @@ -455,6 +454,49 @@ public: } }; +class ArrayOffset : public LVal { + ArrayOffset(const std::pair& data) : LVal(ArrayOffsetKind,&data) {} +public: + + LVal getBase() const { + return reinterpret_cast*> (Data)->first; + } + + const LVal& getPersistentBase() const { + return reinterpret_cast*> (Data)->first; + } + + RVal getOffset() const { + return reinterpret_cast*> (Data)->second; + } + + const RVal& getPersistentOffset() const { + return reinterpret_cast*> (Data)->second; + } + + + // Implement isa support. + static inline bool classof(const RVal* V) { + return V->getBaseKind() == LValKind && + V->getSubKind() == ArrayOffsetKind; + } + + static inline bool classof(const LVal* V) { + return V->getSubKind() == ArrayOffsetKind; + } + + static inline RVal Make(BasicValueFactory& Vals, RVal Base, RVal Offset) { + + if (Base.isUnknownOrUndef()) + return Base; + + if (Offset.isUndef()) + return Offset; + + return ArrayOffset(Vals.getPersistentRValPair(cast(Base), Offset)); + } +}; + } // end clang::lval namespace } // end clang namespace diff --git a/clang/lib/Analysis/BasicValueFactory.cpp b/clang/lib/Analysis/BasicValueFactory.cpp index b0aa79e0670c..8d737a9472de 100644 --- a/clang/lib/Analysis/BasicValueFactory.cpp +++ b/clang/lib/Analysis/BasicValueFactory.cpp @@ -19,6 +19,8 @@ using namespace clang; typedef std::pair RValData; +typedef std::pair RValPair; + namespace llvm { template<> struct FoldingSetTrait { @@ -27,11 +29,21 @@ template<> struct FoldingSetTrait { ID.AddPointer( (void*) X.second); } }; + +template<> struct FoldingSetTrait { + static inline void Profile(const RValPair& X, llvm::FoldingSetNodeID& ID) { + X.first.Profile(ID); + X.second.Profile(ID); + } +}; } typedef llvm::FoldingSet > PersistentRValsTy; +typedef llvm::FoldingSet > + PersistentRValPairsTy; + BasicValueFactory::~BasicValueFactory() { // 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 @@ -40,6 +52,7 @@ BasicValueFactory::~BasicValueFactory() { I->getValue().~APSInt(); delete (PersistentRValsTy*) PersistentRVals; + delete (PersistentRValPairsTy*) PersistentRValPairs; } const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { @@ -208,3 +221,29 @@ BasicValueFactory::getPersistentRValWithData(const RVal& V, uintptr_t Data) { return P->getValue(); } + +const std::pair& +BasicValueFactory::getPersistentRValPair(const RVal& V1, const RVal& V2) { + + // Lazily create the folding set. + if (!PersistentRValPairs) PersistentRValPairs = new PersistentRValPairsTy(); + + llvm::FoldingSetNodeID ID; + void* InsertPos; + V1.Profile(ID); + V2.Profile(ID); + + PersistentRValPairsTy& Map = *((PersistentRValPairsTy*) PersistentRValPairs); + + typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); + + if (!P) { + P = (FoldNodeTy*) BPAlloc.Allocate(); + new (P) FoldNodeTy(std::make_pair(V1, V2)); + Map.InsertNode(P, InsertPos); + } + + return P->getValue(); +} + diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index a4f1a0512d55..a7b31d5b6dd0 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -780,6 +780,7 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred, NodeSet& Dst, bool asLVal) { Expr* Base = A->getBase()->IgnoreParens(); + Expr* Idx = A->getIdx()->IgnoreParens(); // Always visit the base as an LVal expression. This computes the // abstract address of the base object. @@ -790,47 +791,25 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred, else VisitLVal(Base, Pred, Tmp); - // TODO: Compute the LVal for the entry. This will enable array sensitivity - // for the analysis. - - // Return the LVal of the array entry. - if (asLVal) { + for (NodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { - // This is a redunant copy; we do this as a placeholder for future logic. - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - - ValueState* St = GetState(*I); - RVal V = GetRVal(St, Base); - - // TODO: Compute the LVal for the entry. This will enable array sensitivity - // for the analysis. - - if (!(V.isUndef() || V.isUnknown() || isa(V))) - V = UnknownVal(); - - MakeNode(Dst, A, *I, SetRVal(St, A, V)); - } - - return; - } - - // We are doing a load. Check for a bad dereference. In the future we - // will check the actual entry lval; for now, check the Base LVal. For now - // the load will just return "UnknownVal" (since we don't have array - // sensitivity), but it will perform a null check. - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + // Evaluate the index. - ValueState* St = GetState(*I); - RVal V = GetRVal(St, Base); - - // TODO: Compute the LVal for the entry. This will enable array sensitivity - // for the analysis. - - if (!(V.isUndef() || V.isUnknown() || isa(V))) - V = UnknownVal(); - - EvalLoad(Dst, A, *I, St, GetRVal(St, Base), true); + NodeSet Tmp2; + Visit(Idx, *I1, Tmp2); + + for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) { + + ValueState* St = GetState(*I2); + RVal BaseV = GetRVal(St, Base); + RVal IdxV = GetRVal(St, Idx); + RVal V = lval::ArrayOffset::Make(BasicVals, BaseV, IdxV); + + if (asLVal) + MakeNode(Dst, A, *I2, SetRVal(St, A, V)); + else + EvalLoad(Dst, A, *I2, St, V); + } } } @@ -849,36 +828,17 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred, else VisitLVal(Base, Pred, Tmp); - - // Return the LVal of the field access. - if (asLVal) { - - // This is a redunant copy; we do this as a placeholder for future logic. - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - ValueState* St = GetState(*I); - RVal BaseV = GetRVal(St, Base); - - RVal V = lval::FieldOffset::Make(BasicVals, GetRVal(St, Base), - M->getMemberDecl()); - - MakeNode(Dst, M, *I, SetRVal(St, M, V)); - } - - return; - } - - // We are doing a load. Check for a bad dereference. In the future we - // will check the actual field lval; for now, check the Base LVal. For now - // the load will just return "UnknownVal" (since we don't have field - // sensitivity), but it will perform a null check. - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { ValueState* St = GetState(*I); + RVal BaseV = GetRVal(St, Base); RVal V = lval::FieldOffset::Make(BasicVals, GetRVal(St, Base), M->getMemberDecl()); - EvalLoad(Dst, M, *I, St, V, true); + if (asLVal) + MakeNode(Dst, M, *I, SetRVal(St, M, V)); + else + EvalLoad(Dst, M, *I, St, V); } } @@ -2030,6 +1990,10 @@ ValueState* GRExprEngine::AssumeAux(ValueState* St, LVal Cond, return AssumeAux(St, cast(Cond).getBase(), Assumption, isFeasible); + case lval::ArrayOffsetKind: + return AssumeAux(St, cast(Cond).getBase(), + Assumption, isFeasible); + case lval::ConcreteIntKind: { bool b = cast(Cond).getValue() != 0; isFeasible = b ? Assumption : !Assumption; diff --git a/clang/lib/Analysis/RValues.cpp b/clang/lib/Analysis/RValues.cpp index ab1cf6a4207e..85c3b23efd04 100644 --- a/clang/lib/Analysis/RValues.cpp +++ b/clang/lib/Analysis/RValues.cpp @@ -415,6 +415,15 @@ void LVal::print(std::ostream& Out) const { break; } + case lval::ArrayOffsetKind: { + const lval::ArrayOffset& C = *cast(this); + C.getBase().print(Out); + Out << "["; + C.getOffset().print(Out); + Out << "] (lval array entry)"; + break; + } + default: assert (false && "Pretty-printing not implemented for this LVal."); break; diff --git a/clang/lib/Analysis/ValueState.cpp b/clang/lib/Analysis/ValueState.cpp index e51366d66631..edc5b6d00480 100644 --- a/clang/lib/Analysis/ValueState.cpp +++ b/clang/lib/Analysis/ValueState.cpp @@ -212,6 +212,7 @@ RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) { return UnknownVal(); } + case lval::ArrayOffsetKind: case lval::FieldOffsetKind: return UnknownVal();