From: Ted Kremenek Date: Tue, 22 Apr 2008 21:10:18 +0000 (+0000) Subject: Added "nonlval::LValAsInteger" to represent abstract LVals casted to integers, allowi... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0fe33bc94a822e315585e5cde1964d3c3b9052f9;p=clang Added "nonlval::LValAsInteger" to represent abstract LVals casted to integers, allowing us to track lvals when they are casted back to pointers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50108 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h index 351e326344..9462ed597d 100644 --- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -27,22 +27,26 @@ namespace llvm { namespace clang { +class RVal; + class BasicValueFactory { typedef llvm::FoldingSet > APSIntSetTy; typedef llvm::FoldingSet SymIntCSetTy; + ASTContext& Ctx; llvm::BumpPtrAllocator& BPAlloc; APSIntSetTy APSIntSet; SymIntCSetTy SymIntCSet; + void* PersistentRVals; public: BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) - : Ctx(ctx), BPAlloc(Alloc) {} + : Ctx(ctx), BPAlloc(Alloc), PersistentRVals(0) {} ~BasicValueFactory(); @@ -66,6 +70,9 @@ public: const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt& V1, const llvm::APSInt& V2); + + const std::pair& + getPersistentSizedRVal(const RVal& V, unsigned Bits); }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/RValues.h b/include/clang/Analysis/PathSensitive/RValues.h index dd99a2ee79..45a5452ffc 100644 --- a/include/clang/Analysis/PathSensitive/RValues.h +++ b/include/clang/Analysis/PathSensitive/RValues.h @@ -163,7 +163,8 @@ public: namespace nonlval { -enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind }; +enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind, + LValAsIntegerKind }; class SymbolVal : public NonLVal { public: @@ -230,6 +231,40 @@ public: } }; +class LValAsInteger : public NonLVal { + LValAsInteger(const std::pair& data) : + NonLVal(LValAsIntegerKind, &data) {} + +public: + + LVal getLVal() const { + return cast(((std::pair*) Data)->first); + } + + const LVal& getPersistentLVal() const { + return cast(((std::pair*) Data)->first); + } + + unsigned getNumBits() const { + return ((std::pair*) Data)->second; + } + + // Implement isa support. + static inline bool classof(const RVal* V) { + return V->getBaseKind() == NonLValKind && + V->getSubKind() == LValAsIntegerKind; + } + + static inline bool classof(const NonLVal* V) { + return V->getSubKind() == LValAsIntegerKind; + } + + static inline LValAsInteger Make(BasicValueFactory& Vals, LVal V, + unsigned Bits) { + return LValAsInteger(Vals.getPersistentSizedRVal(V, Bits)); + } +}; + } // end namespace clang::nonlval //==------------------------------------------------------------------------==// diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Analysis/BasicValueFactory.cpp index 88b360d1d0..22fb2d1b6e 100644 --- a/lib/Analysis/BasicValueFactory.cpp +++ b/lib/Analysis/BasicValueFactory.cpp @@ -14,15 +14,32 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/BasicValueFactory.h" +#include "clang/Analysis/PathSensitive/RValues.h" using namespace clang; +typedef std::pair SizedRVal; + +namespace llvm { +template<> struct FoldingSetTrait { + static inline void Profile(const SizedRVal& X, llvm::FoldingSetNodeID& ID) { + X.first.Profile(ID); + ID.AddInteger(X.second); + } +}; +} + +typedef llvm::FoldingSet > + PersistentRValsTy; + 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 // 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(); + + delete (PersistentRValsTy*) PersistentRVals; } const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { @@ -165,3 +182,29 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, return &getValue( V1 ^ V2 ); } } + + +const std::pair& +BasicValueFactory::getPersistentSizedRVal(const RVal& V, unsigned Bits) { + + // Lazily create the folding set. + if (!PersistentRVals) PersistentRVals = new PersistentRValsTy(); + + llvm::FoldingSetNodeID ID; + void* InsertPos; + V.Profile(ID); + ID.AddInteger(Bits); + + PersistentRValsTy& Map = *((PersistentRValsTy*) PersistentRVals); + + typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); + + if (!P) { + P = (FoldNodeTy*) BPAlloc.Allocate(); + new (P) FoldNodeTy(std::make_pair(V, Bits)); + Map.InsertNode(P, InsertPos); + } + + return *P; +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 4c77b6460a..bdb742929d 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -1102,10 +1102,8 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ else Visit(Ex, Pred, S1); - // Check for redundant casts or casting to "void" - if (T->isVoidType() || - Ex->getType() == T || - (T->isPointerType() && Ex->getType()->isFunctionType())) { + // Check for casting to "void". + if (T->isVoidType()) { for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) Dst.Add(*I1); @@ -1113,11 +1111,54 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ return; } + // FIXME: The rest of this should probably just go into EvalCall, and + // let the transfer function object be responsible for constructing + // nodes. + + QualType ExTy = Ex->getType(); + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { NodeTy* N = *I1; ValueState* St = GetState(N); - RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex); + + // Unknown? + + if (V.isUnknown()) { + Dst.Add(N); + continue; + } + + // Undefined? + + if (V.isUndef()) { + MakeNode(Dst, CastE, N, SetRVal(St, CastE, V)); + continue; + } + + // Check for casts from pointers to integers. + if (T->isIntegerType() && ExTy->isPointerType()) { + unsigned bits = getContext().getTypeSize(ExTy); + + // FIXME: Determine if the number of bits of the target type is + // equal or exceeds the number of bits to store the pointer value. + // If not, flag an error. + + V = nonlval::LValAsInteger::Make(BasicVals, cast(V), bits); + MakeNode(Dst, CastE, N, SetRVal(St, CastE, V)); + continue; + } + + // Check for casts from integers to pointers. + if (T->isPointerType() && ExTy->isIntegerType()) + if (nonlval::LValAsInteger *LV = dyn_cast(&V)) { + // Just unpackage the lval and return it. + V = LV->getLVal(); + MakeNode(Dst, CastE, N, SetRVal(St, CastE, V)); + continue; + } + + // All other cases. MakeNode(Dst, CastE, N, SetRVal(St, CastE, EvalCast(V, CastE->getType()))); } @@ -2024,6 +2065,11 @@ ValueState* GRExprEngine::AssumeAux(ValueState* St, NonLVal Cond, isFeasible = b ? Assumption : !Assumption; return St; } + + case nonlval::LValAsIntegerKind: { + return AssumeAux(St, cast(Cond).getLVal(), + Assumption, isFeasible); + } } } diff --git a/lib/Analysis/RValues.cpp b/lib/Analysis/RValues.cpp index 2e44e7086c..86f5ac96fd 100644 --- a/lib/Analysis/RValues.cpp +++ b/lib/Analysis/RValues.cpp @@ -35,6 +35,10 @@ RVal::symbol_iterator RVal::symbol_begin() const { return (symbol_iterator) &C.getSymbol(); } + else if (isa(this)) { + const nonlval::LValAsInteger& V = cast(*this); + return V.getPersistentLVal().symbol_begin(); + } return NULL; } @@ -345,7 +349,14 @@ void NonLVal::print(std::ostream& Out) const { Out << 'U'; break; - } + } + + case nonlval::LValAsIntegerKind: { + const nonlval::LValAsInteger& C = *cast(this); + C.getLVal().print(Out); + Out << " [as " << C.getNumBits() << " bit integer]"; + break; + } default: assert (false && "Pretty-printed not implemented for this NonLVal."); diff --git a/lib/Analysis/ValueState.cpp b/lib/Analysis/ValueState.cpp index c0ed7aa882..bba2e06a18 100644 --- a/lib/Analysis/ValueState.cpp +++ b/lib/Analysis/ValueState.cpp @@ -277,12 +277,7 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) { return UnknownVal(); QualType ST = C->getSubExpr()->getType(); - - if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { - E = C->getSubExpr(); - continue; - } - + break; } @@ -294,11 +289,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) { if (CT->isVoidType()) return UnknownVal(); - if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { - E = C->getSubExpr(); - continue; - } - break; } diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c index b78c93ad16..6d954fd957 100644 --- a/test/Analysis/null-deref-ps.c +++ b/test/Analysis/null-deref-ps.c @@ -1,5 +1,7 @@ // RUN: clang -checker-simple -verify %s +#include + void f1(int *p) { if (p) *p = 1; else *p = 0; // expected-warning{{ereference}} @@ -27,3 +29,13 @@ int f3(char* x) { return x[i+1]; // expected-warning{{Dereference of null pointer.}} } +int f4(int *p) { + + uintptr_t x = p; + + if (x) + return 1; + + int *q = (int*) x; + return *q; // expected-warning{{Dereference of null pointer.}} +} \ No newline at end of file