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
This commit is contained in:
Ted Kremenek 2008-04-22 21:10:18 +00:00
Родитель 9fdf9c6d35
Коммит 0fe33bc94a
7 изменённых файлов: 163 добавлений и 19 удалений

Просмотреть файл

@ -27,6 +27,8 @@ namespace llvm {
namespace clang { namespace clang {
class RVal;
class BasicValueFactory { class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy; APSIntSetTy;
@ -34,15 +36,17 @@ class BasicValueFactory {
typedef llvm::FoldingSet<SymIntConstraint> typedef llvm::FoldingSet<SymIntConstraint>
SymIntCSetTy; SymIntCSetTy;
ASTContext& Ctx; ASTContext& Ctx;
llvm::BumpPtrAllocator& BPAlloc; llvm::BumpPtrAllocator& BPAlloc;
APSIntSetTy APSIntSet; APSIntSetTy APSIntSet;
SymIntCSetTy SymIntCSet; SymIntCSetTy SymIntCSet;
void* PersistentRVals;
public: public:
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc) {} : Ctx(ctx), BPAlloc(Alloc), PersistentRVals(0) {}
~BasicValueFactory(); ~BasicValueFactory();
@ -66,6 +70,9 @@ public:
const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
const llvm::APSInt& V1, const llvm::APSInt& V1,
const llvm::APSInt& V2); const llvm::APSInt& V2);
const std::pair<RVal, unsigned>&
getPersistentSizedRVal(const RVal& V, unsigned Bits);
}; };
} // end clang namespace } // end clang namespace

Просмотреть файл

@ -163,7 +163,8 @@ public:
namespace nonlval { namespace nonlval {
enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind }; enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind,
LValAsIntegerKind };
class SymbolVal : public NonLVal { class SymbolVal : public NonLVal {
public: public:
@ -230,6 +231,40 @@ public:
} }
}; };
class LValAsInteger : public NonLVal {
LValAsInteger(const std::pair<RVal, unsigned>& data) :
NonLVal(LValAsIntegerKind, &data) {}
public:
LVal getLVal() const {
return cast<LVal>(((std::pair<RVal, unsigned>*) Data)->first);
}
const LVal& getPersistentLVal() const {
return cast<LVal>(((std::pair<RVal, unsigned>*) Data)->first);
}
unsigned getNumBits() const {
return ((std::pair<RVal, unsigned>*) Data)->second;
}
// Implement isa<T> 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 } // end namespace clang::nonlval
//==------------------------------------------------------------------------==// //==------------------------------------------------------------------------==//

Просмотреть файл

@ -14,15 +14,32 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/BasicValueFactory.h" #include "clang/Analysis/PathSensitive/BasicValueFactory.h"
#include "clang/Analysis/PathSensitive/RValues.h"
using namespace clang; using namespace clang;
typedef std::pair<RVal, unsigned> SizedRVal;
namespace llvm {
template<> struct FoldingSetTrait<SizedRVal> {
static inline void Profile(const SizedRVal& X, llvm::FoldingSetNodeID& ID) {
X.first.Profile(ID);
ID.AddInteger(X.second);
}
};
}
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SizedRVal> >
PersistentRValsTy;
BasicValueFactory::~BasicValueFactory() { BasicValueFactory::~BasicValueFactory() {
// Note that the dstor for the contents of APSIntSet will never be called, // 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 // so we iterate over the set and invoke the dstor for each APSInt. This
// frees an aux. memory allocated to represent very large constants. // frees an aux. memory allocated to represent very large constants.
for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I)
I->getValue().~APSInt(); I->getValue().~APSInt();
delete (PersistentRValsTy*) PersistentRVals;
} }
const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) {
@ -165,3 +182,29 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op,
return &getValue( V1 ^ V2 ); return &getValue( V1 ^ V2 );
} }
} }
const std::pair<RVal, unsigned>&
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<SizedRVal> FoldNodeTy;
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(std::make_pair(V, Bits));
Map.InsertNode(P, InsertPos);
}
return *P;
}

Просмотреть файл

@ -1102,10 +1102,8 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
else else
Visit(Ex, Pred, S1); Visit(Ex, Pred, S1);
// Check for redundant casts or casting to "void" // Check for casting to "void".
if (T->isVoidType() || if (T->isVoidType()) {
Ex->getType() == T ||
(T->isPointerType() && Ex->getType()->isFunctionType())) {
for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
Dst.Add(*I1); Dst.Add(*I1);
@ -1113,12 +1111,55 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
return; 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) { for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
NodeTy* N = *I1; NodeTy* N = *I1;
ValueState* St = GetState(N); ValueState* St = GetState(N);
RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex); 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<LVal>(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<nonlval::LValAsInteger>(&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()))); 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; isFeasible = b ? Assumption : !Assumption;
return St; return St;
} }
case nonlval::LValAsIntegerKind: {
return AssumeAux(St, cast<nonlval::LValAsInteger>(Cond).getLVal(),
Assumption, isFeasible);
}
} }
} }

Просмотреть файл

@ -35,6 +35,10 @@ RVal::symbol_iterator RVal::symbol_begin() const {
return (symbol_iterator) &C.getSymbol(); return (symbol_iterator) &C.getSymbol();
} }
else if (isa<nonlval::LValAsInteger>(this)) {
const nonlval::LValAsInteger& V = cast<nonlval::LValAsInteger>(*this);
return V.getPersistentLVal().symbol_begin();
}
return NULL; return NULL;
} }
@ -347,6 +351,13 @@ void NonLVal::print(std::ostream& Out) const {
break; break;
} }
case nonlval::LValAsIntegerKind: {
const nonlval::LValAsInteger& C = *cast<nonlval::LValAsInteger>(this);
C.getLVal().print(Out);
Out << " [as " << C.getNumBits() << " bit integer]";
break;
}
default: default:
assert (false && "Pretty-printed not implemented for this NonLVal."); assert (false && "Pretty-printed not implemented for this NonLVal.");
break; break;

Просмотреть файл

@ -278,11 +278,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) {
QualType ST = C->getSubExpr()->getType(); QualType ST = C->getSubExpr()->getType();
if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
E = C->getSubExpr();
continue;
}
break; break;
} }
@ -294,11 +289,6 @@ RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) {
if (CT->isVoidType()) if (CT->isVoidType())
return UnknownVal(); return UnknownVal();
if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
E = C->getSubExpr();
continue;
}
break; break;
} }

Просмотреть файл

@ -1,5 +1,7 @@
// RUN: clang -checker-simple -verify %s // RUN: clang -checker-simple -verify %s
#include<stdint.h>
void f1(int *p) { void f1(int *p) {
if (p) *p = 1; if (p) *p = 1;
else *p = 0; // expected-warning{{ereference}} else *p = 0; // expected-warning{{ereference}}
@ -27,3 +29,13 @@ int f3(char* x) {
return x[i+1]; // expected-warning{{Dereference of null pointer.}} 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.}}
}