Fix a couple bugs:

- NonLoc::MakeVal() would use sizeof(unsigned) (literally) instead of consulting
  ASTContext for the size (in bits) of 'int'. While it worked, it was a
  conflation of concepts and using ASTContext.IntTy is 100% correct.
- RegionStore::getSizeInElements() no longer assumes that a VarRegion has the
  type "ConstantArray", and handles the case when uses use ordinary variables
  as if they were arrays.
- Fixed ElementRegion::getRValueType() to just return the rvalue type of its
  "array region" in the case the array didn't have ArrayType.
- All of this fixes <rdar://problem/6541136>

llvm-svn: 63347
This commit is contained in:
Ted Kremenek 2009-01-30 00:08:43 +00:00
parent 711e882c1b
commit 7594e2a59a
8 changed files with 78 additions and 19 deletions

View File

@ -76,6 +76,11 @@ public:
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
return getValue(X, T);
}
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}

View File

@ -173,6 +173,14 @@ public:
// FIXME: We can possibly optimize this later to cache this value.
return C.getPointerType(getRValueType(C));
}
QualType getDesugaredRValueType(ASTContext& C) const {
return getRValueType(C)->getDesugaredType();
}
QualType getDesugaredLValueType(ASTContext& C) const {
return getLValueType(C)->getDesugaredType();
}
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();

View File

@ -171,8 +171,8 @@ public:
static NonLoc MakeVal(SymbolRef sym);
static NonLoc MakeVal(BasicValueFactory& BasicVals, unsigned X,
bool isUnsigned);
static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
bool isUnsigned);
static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X,
unsigned BitWidth, bool isUnsigned);

View File

@ -114,8 +114,9 @@ QualType ElementRegion::getRValueType(ASTContext& C) const {
if (ArrayType* AT = dyn_cast<ArrayType>(T.getTypePtr()))
return AT->getElementType();
PointerType* PtrT = cast<PointerType>(T.getTypePtr());
return C.getCanonicalType(PtrT->getPointeeType());
// If the RValueType of the array region isn't an ArrayType, then essentially
// the element's
return T;
}
//===----------------------------------------------------------------------===//

View File

@ -403,20 +403,27 @@ SVal RegionStoreManager::getSizeInElements(const GRState* St,
const MemRegion* R) {
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
// Get the type of the variable.
QualType T = VR->getRValueType(getContext());
QualType T = VR->getDesugaredRValueType(getContext());
// It must be of array type.
const ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
// return the size as signed integer.
return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false);
// FIXME: Handle variable-length arrays.
if (isa<VariableArrayType>(T))
return UnknownVal();
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
// return the size as signed integer.
return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false);
}
// Clients can use ordinary variables as if they were arrays. These
// essentially are arrays of size 1.
return NonLoc::MakeIntVal(getBasicVals(), 1, false);
}
if (const StringRegion* SR = dyn_cast<StringRegion>(R)) {
const StringLiteral* Str = SR->getStringLiteral();
// We intentionally made the size value signed because it participates in
// operations with signed indices.
return NonLoc::MakeVal(getBasicVals(), Str->getByteLength() + 1, false);
return NonLoc::MakeIntVal(getBasicVals(), Str->getByteLength()+1, false);
}
if (const AnonTypedRegion* ATR = dyn_cast<AnonTypedRegion>(R)) {
@ -880,8 +887,8 @@ const GRState* RegionStoreManager::BindArray(const GRState* St,
// When we are binding the whole array, it always has default value 0.
GRStateRef state(St, StateMgr);
St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0,
false));
St = state.set<RegionDefaultValue>(R, NonLoc::MakeIntVal(getBasicVals(), 0,
false));
Store store = St->getStore();
@ -961,8 +968,8 @@ RegionStoreManager::BindStruct(const GRState* St, const TypedRegion* R, SVal V){
// struct decl. In this case, mark the region as having default value.
if (VI == VE) {
GRStateRef state(St, StateMgr);
St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0,
false));
const NonLoc& Idx = NonLoc::MakeIntVal(getBasicVals(), 0, false);
St = state.set<RegionDefaultValue>(R, Idx);
break;
}

View File

@ -247,10 +247,9 @@ NonLoc NonLoc::MakeVal(SymbolRef sym) {
return nonloc::SymbolVal(sym);
}
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, unsigned X,
bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(X, sizeof(unsigned)*8,
isUnsigned));
NonLoc NonLoc::MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
}
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X,

View File

@ -0,0 +1,19 @@
// RUN: clang -verify -analyze -checker-cfref -analyzer-store-region %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
extern kernel_tea_cheese_t _wonky_gesticulate_cheese;
// This test case exercises the ElementRegion::getRValueType() logic.
void foo( void )
{
kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese;
struct load_wine *cmd = (void*) &wonky[1];
cmd = cmd;
char *p = (void*) &wonky[1];
*p = 1;
kernel_tea_cheese_t *q = &wonky[1];
kernel_tea_cheese_t r = *q; // expected-warning{{out-of-bound memory position}}
}

View File

@ -0,0 +1,20 @@
// clang -verify -analyze -checker-cfref -analyzer-store-basic %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
extern kernel_tea_cheese_t _wonky_gesticulate_cheese;
// This test case exercises the ElementRegion::getRValueType() logic.
// All it tests is that it does not crash or do anything weird.
// The out-of-bounds-access on line 19 is caught using the region store variant.
void foo( void )
{
kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese;
struct load_wine *cmd = (void*) &wonky[1];
cmd = cmd;
char *p = (void*) &wonky[1];
*p = 1;
kernel_tea_cheese_t *q = &wonky[1];
kernel_tea_cheese_t r = *q; // no-warning
}