Teach RegionStore to handle initialization of incomplete arrays in structures using a compound value. Fixes <rdar://problem/7515938>.

llvm-svn: 94622
This commit is contained in:
Ted Kremenek 2010-01-26 23:51:00 +00:00
parent dbf5a7617d
commit e36bceb97d
3 changed files with 55 additions and 12 deletions

View File

@ -20,7 +20,7 @@ namespace clang {
template<typename T>
class Optional {
const T x;
T x;
unsigned hasVal : 1;
public:
explicit Optional() : hasVal(false) {}
@ -30,9 +30,17 @@ public:
return y ? Optional(*y) : Optional();
}
Optional &operator=(const T &y) {
x = y;
hasVal = true;
return *this;
}
const T* getPointer() const { assert(hasVal); return &x; }
const T& getValue() const { assert(hasVal); return x; }
operator bool() const { return hasVal; }
bool hasValue() const { return hasVal; }
const T* operator->() const { return getPointer(); }
const T& operator*() const { assert(hasVal); return x; }
};

View File

@ -1572,13 +1572,16 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
const GRState *RegionStoreManager::BindArray(const GRState *state,
const TypedRegion* R,
SVal Init) {
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
QualType ElementTy = CAT->getElementType();
uint64_t size = CAT->getSize().getZExtValue();
ASTContext &Ctx = getContext();
const ArrayType *AT =
cast<ArrayType>(Ctx.getCanonicalType(R->getValueType(Ctx)));
QualType ElementTy = AT->getElementType();
Optional<uint64_t> Size;
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
Size = CAT->getSize().getZExtValue();
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion();
@ -1590,6 +1593,11 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
// We assume that string constants are bound to
// constant arrays.
uint64_t size = Size;
for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
@ -1618,7 +1626,7 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
for (; i < size; ++i, ++VI) {
for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
break;
@ -1626,16 +1634,15 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
if (CAT->getElementType()->isStructureType())
if (ElementTy->isStructureType())
state = BindStruct(state, ER, *VI);
else
// FIXME: Do we need special handling of nested arrays?
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the
// array default value.
if (i < size)
if (Size.hasValue() && i < Size.getValue())
state = setImplicitDefaultValue(state, R, ElementTy);
return state;

View File

@ -730,3 +730,31 @@ void rdar_7527292() {
}
}
//===----------------------------------------------------------------------===//
// <rdar://problem/7515938> - Handle initialization of incomplete arrays
// in structures using a compound value. Previously this crashed.
//===----------------------------------------------------------------------===//
struct rdar_7515938 {
int x;
int y[];
};
const struct rdar_7515938 *rdar_7515938() {
static const struct rdar_7515938 z = { 0, { 1, 2 } };
if (z.y[0] != 1) {
int *p = 0;
*p = 0xDEADBEEF; // no-warning
}
return &z;
}
struct rdar_7515938_str {
int x;
char y[];
};
const struct rdar_7515938_str *rdar_7515938_str() {
static const struct rdar_7515938_str z = { 0, "hello" };
return &z;
}