diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 46 | ||||
-rw-r--r-- | test/Analysis/array-struct-region.c | 39 |
2 files changed, 68 insertions, 17 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index a8e47ff8e2..fa26c13203 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1447,16 +1447,27 @@ SVal RegionStoreManager::getBindingForLazySymbol(const TypedValueRegion *R) { return svalBuilder.getRegionValueSymbolVal(R); } +static bool mayHaveLazyBinding(QualType Ty) { + return Ty->isArrayType() || Ty->isStructureOrClassType(); +} + SVal RegionStoreManager::getBindingForStruct(Store store, const TypedValueRegion* R) { - assert(R->getValueType()->isStructureOrClassType()); - - // If we already have a lazy binding, don't create a new one. - RegionBindings B = GetRegionBindings(store); - BindingKey K = BindingKey::Make(R, BindingKey::Default); - if (const nonloc::LazyCompoundVal *V = - dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) { - return *V; + const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl(); + if (RD->field_empty()) + return UnknownVal(); + + // If we already have a lazy binding, don't create a new one, + // unless the first field might have a lazy binding of its own. + // (Right now we can't tell the difference.) + QualType FirstFieldType = RD->field_begin()->getType(); + if (!mayHaveLazyBinding(FirstFieldType)) { + RegionBindings B = GetRegionBindings(store); + BindingKey K = BindingKey::Make(R, BindingKey::Default); + if (const nonloc::LazyCompoundVal *V = + dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) { + return *V; + } } return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); @@ -1464,14 +1475,19 @@ SVal RegionStoreManager::getBindingForStruct(Store store, SVal RegionStoreManager::getBindingForArray(Store store, const TypedValueRegion * R) { - assert(Ctx.getAsConstantArrayType(R->getValueType())); + const ConstantArrayType *Ty = Ctx.getAsConstantArrayType(R->getValueType()); + assert(Ty && "Only constant array types can have compound bindings."); - // If we already have a lazy binding, don't create a new one. - RegionBindings B = GetRegionBindings(store); - BindingKey K = BindingKey::Make(R, BindingKey::Default); - if (const nonloc::LazyCompoundVal *V = - dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) { - return *V; + // If we already have a lazy binding, don't create a new one, + // unless the first element might have a lazy binding of its own. + // (Right now we can't tell the difference.) + if (!mayHaveLazyBinding(Ty->getElementType())) { + RegionBindings B = GetRegionBindings(store); + BindingKey K = BindingKey::Make(R, BindingKey::Default); + if (const nonloc::LazyCompoundVal *V = + dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) { + return *V; + } } return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c index c1eddcdd21..ddb9f4b116 100644 --- a/test/Analysis/array-struct-region.c +++ b/test/Analysis/array-struct-region.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -analyzer-ipa=all -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -analyzer-ipa=all -verify %s void clang_analyzer_eval(int); @@ -57,3 +57,38 @@ void struct_as_array() { clang_analyzer_eval(p->y == 5); // expected-warning{{TRUE}} } + +// PR13264 / <rdar://problem/11802440> +struct point { int x; int y; }; +struct circle { struct point o; int r; }; +struct circle get_circle() { + struct circle result; + result.r = 5; + result.o = (struct point){0, 0}; + return result; +} + +void struct_in_struct() { + struct circle c; + c = get_circle(); + // This used to think c.r was undefined because c.o is a LazyCompoundVal. + clang_analyzer_eval(c.r == 5); // expected-warning{{TRUE}} +} + +// We also test with floats because we don't model floats right now, +// and the original bug report used a float. +struct circle_f { struct point o; float r; }; +struct circle_f get_circle_f() { + struct circle_f result; + result.r = 5.0; + result.o = (struct point){0, 0}; + return result; +} + +float struct_in_struct_f() { + struct circle_f c; + c = get_circle_f(); + + return c.r; // no-warning +} + |