Add lval::ArrayOffset, which represent the locations of entries in an array.

llvm-svn: 50453
This commit is contained in:
Ted Kremenek 2008-04-29 23:24:44 +00:00
parent 2dfcec129f
commit 10246e8bfa
6 changed files with 127 additions and 68 deletions

View File

@ -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<RVal, uintptr_t>&
getPersistentRValWithData(const RVal& V, uintptr_t Data);
const std::pair<RVal, RVal>&
getPersistentRValPair(const RVal& V1, const RVal& V2);
};
} // end clang namespace

View File

@ -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<RVal, uintptr_t>& data)
: LVal(FieldOffsetKind, &data) {
assert (isa<LVal>(data.first));
}
: LVal(FieldOffsetKind, &data) {}
public:
@ -455,6 +454,49 @@ public:
}
};
class ArrayOffset : public LVal {
ArrayOffset(const std::pair<RVal,RVal>& data) : LVal(ArrayOffsetKind,&data) {}
public:
LVal getBase() const {
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->first;
}
const LVal& getPersistentBase() const {
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->first;
}
RVal getOffset() const {
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->second;
}
const RVal& getPersistentOffset() const {
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->second;
}
// Implement isa<T> 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<LVal>(Base), Offset));
}
};
} // end clang::lval namespace
} // end clang namespace

View File

@ -19,6 +19,8 @@
using namespace clang;
typedef std::pair<RVal, uintptr_t> RValData;
typedef std::pair<RVal, RVal> RValPair;
namespace llvm {
template<> struct FoldingSetTrait<RValData> {
@ -27,11 +29,21 @@ template<> struct FoldingSetTrait<RValData> {
ID.AddPointer( (void*) X.second);
}
};
template<> struct FoldingSetTrait<RValPair> {
static inline void Profile(const RValPair& X, llvm::FoldingSetNodeID& ID) {
X.first.Profile(ID);
X.second.Profile(ID);
}
};
}
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<RValData> >
PersistentRValsTy;
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<RValPair> >
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<RVal, RVal>&
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<RValPair> FoldNodeTy;
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
new (P) FoldNodeTy(std::make_pair(V1, V2));
Map.InsertNode(P, InsertPos);
}
return P->getValue();
}

View File

@ -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<lval::ConcreteInt>(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<lval::ConcreteInt>(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<lval::FieldOffset>(Cond).getBase(),
Assumption, isFeasible);
case lval::ArrayOffsetKind:
return AssumeAux(St, cast<lval::ArrayOffset>(Cond).getBase(),
Assumption, isFeasible);
case lval::ConcreteIntKind: {
bool b = cast<lval::ConcreteInt>(Cond).getValue() != 0;
isFeasible = b ? Assumption : !Assumption;

View File

@ -415,6 +415,15 @@ void LVal::print(std::ostream& Out) const {
break;
}
case lval::ArrayOffsetKind: {
const lval::ArrayOffset& C = *cast<lval::ArrayOffset>(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;

View File

@ -212,6 +212,7 @@ RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) {
return UnknownVal();
}
case lval::ArrayOffsetKind:
case lval::FieldOffsetKind:
return UnknownVal();