зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
9fdf9c6d35
Коммит
0fe33bc94a
|
@ -27,22 +27,26 @@ namespace llvm {
|
|||
|
||||
namespace clang {
|
||||
|
||||
class RVal;
|
||||
|
||||
class BasicValueFactory {
|
||||
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
|
||||
APSIntSetTy;
|
||||
|
||||
typedef llvm::FoldingSet<SymIntConstraint>
|
||||
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<RVal, unsigned>&
|
||||
getPersistentSizedRVal(const RVal& V, unsigned Bits);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
@ -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<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
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
|
|
@ -14,15 +14,32 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
|
||||
#include "clang/Analysis/PathSensitive/RValues.h"
|
||||
|
||||
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() {
|
||||
// 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<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
|
||||
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<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())));
|
||||
}
|
||||
|
@ -2024,6 +2065,11 @@ ValueState* GRExprEngine::AssumeAux(ValueState* St, NonLVal Cond,
|
|||
isFeasible = b ? Assumption : !Assumption;
|
||||
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();
|
||||
}
|
||||
else if (isa<nonlval::LValAsInteger>(this)) {
|
||||
const nonlval::LValAsInteger& V = cast<nonlval::LValAsInteger>(*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<nonlval::LValAsInteger>(this);
|
||||
C.getLVal().print(Out);
|
||||
Out << " [as " << C.getNumBits() << " bit integer]";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert (false && "Pretty-printed not implemented for this NonLVal.");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// RUN: clang -checker-simple -verify %s
|
||||
|
||||
#include<stdint.h>
|
||||
|
||||
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.}}
|
||||
}
|
Загрузка…
Ссылка в новой задаче