Add lval::ArrayOffset, which represent the locations of entries in an array.
llvm-svn: 50453
This commit is contained in:
parent
2dfcec129f
commit
10246e8bfa
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -212,6 +212,7 @@ RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) {
|
|||
return UnknownVal();
|
||||
}
|
||||
|
||||
case lval::ArrayOffsetKind:
|
||||
case lval::FieldOffsetKind:
|
||||
return UnknownVal();
|
||||
|
||||
|
|
Loading…
Reference in New Issue