Fix insidious RegionStore bug where we (a) didn't handle vector types and (b) had

a horrible bug in GetLazyBindings where we falsely appended a field suffix when traversing 3 or more
layers of lazy bindings.  I don't have a reduced test case yet; but I have added the original source
to an internal regression test suite.  I'll see about coming up with a reduced test case.

Fixes <rdar://problem/11405978> (for real).

llvm-svn: 156580
This commit is contained in:
Ted Kremenek 2012-05-10 22:02:39 +00:00
parent 4fe10a5d9a
commit 77cbb8481b
1 changed files with 68 additions and 10 deletions

View File

@ -302,6 +302,9 @@ public: // Part of public interface to class.
/// BindStruct - Bind a compound value to a structure.
StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
/// BindVector - Bind a compound value to a vector.
StoreRef BindVector(Store store, const TypedValueRegion* R, SVal V);
StoreRef BindArray(Store store, const TypedValueRegion* R, SVal V);
/// KillStruct - Set the entire struct to unknown.
@ -372,7 +375,8 @@ public: // Part of public interface to class.
/// Get the state and region whose binding this region R corresponds to.
std::pair<Store, const MemRegion*>
GetLazyBinding(RegionBindings B, const MemRegion *R,
const MemRegion *originalRegion);
const MemRegion *originalRegion,
bool includeSuffix = false);
StoreRef CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
const TypedRegion *R);
@ -1108,7 +1112,8 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
std::pair<Store, const MemRegion *>
RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
const MemRegion *originalRegion) {
const MemRegion *originalRegion,
bool includeSuffix) {
if (originalRegion != R) {
if (Optional<SVal> OV = getDefaultBinding(B, R)) {
@ -1130,9 +1135,13 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, FR->getSuperRegion(), originalRegion);
if (X.second)
return std::make_pair(X.first,
MRMgr.getFieldRegionWithSuper(FR, X.second));
if (X.second) {
if (includeSuffix)
return std::make_pair(X.first,
MRMgr.getFieldRegionWithSuper(FR, X.second));
return X;
}
}
// C++ base object region is another kind of region that we should blast
// through to look for lazy compound value. It is like a field region.
@ -1141,9 +1150,13 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, baseReg->getSuperRegion(), originalRegion);
if (X.second)
return std::make_pair(X.first,
MRMgr.getCXXBaseObjectRegionWithSuper(baseReg, X.second));
if (X.second) {
if (includeSuffix)
return std::make_pair(X.first,
MRMgr.getCXXBaseObjectRegionWithSuper(baseReg,
X.second));
return X;
}
}
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
@ -1492,9 +1505,13 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
// Check if the region is a struct region.
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R))
if (TR->getValueType()->isStructureOrClassType())
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
QualType Ty = TR->getValueType();
if (Ty->isStructureOrClassType())
return BindStruct(store, TR, V);
if (Ty->isVectorType())
return BindVector(store, TR, V);
}
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
if (ER->getIndex().isZeroConstant()) {
@ -1638,6 +1655,47 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
return newStore;
}
StoreRef RegionStoreManager::BindVector(Store store, const TypedValueRegion* R,
SVal V) {
QualType T = R->getValueType();
assert(T->isVectorType());
const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
// Handle lazy compound values.
if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&V))
return CopyLazyBindings(*LCV, store, R);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding.
if (V.isUnknown() || !isa<nonloc::CompoundVal>(V)) {
SVal SV = isa<nonloc::SymbolVal>(V) ? V : UnknownVal();
return KillStruct(store, R, SV);
}
QualType ElemType = VT->getElementType();
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
unsigned index = 0, numElements = VT->getNumElements();
StoreRef newStore(store, *this);
for ( ; index != numElements ; ++index) {
if (VI == VE)
break;
NonLoc Idx = svalBuilder.makeArrayIndex(index);
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
if (ElemType->isArrayType())
newStore = BindArray(newStore.getStore(), ER, *VI);
else if (ElemType->isStructureOrClassType())
newStore = BindStruct(newStore.getStore(), ER, *VI);
else
newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(ER), *VI);
}
return newStore;
}
StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
SVal V) {