/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal getBindingForStruct(RegionBindingsConstRef B, const TypedValueRegion* R);
-
- SVal getBindingForArray(RegionBindingsConstRef B, const TypedValueRegion* R);
+ SVal getBindingForStruct(RegionBindingsConstRef B, const TypedValueRegion *R);
+ SVal getBindingForArray(RegionBindingsConstRef B, const TypedValueRegion *R);
+ NonLoc createLazyBinding(RegionBindingsConstRef B, const TypedValueRegion *R);
/// Used to lazily generate derived symbols for bindings that are defined
/// implicitly by default bindings in a super region.
return svalBuilder.getRegionValueSymbolVal(R);
}
-static bool mayHaveLazyBinding(QualType Ty) {
- return Ty->isArrayType() || Ty->isStructureOrClassType();
+NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
+ // If we already have a lazy binding, and it's for the whole structure,
+ // don't create a new lazy binding.
+ if (Optional<SVal> V = B.getDefaultBinding(R)) {
+ const nonloc::LazyCompoundVal *LCV =
+ dyn_cast<nonloc::LazyCompoundVal>(V.getPointer());
+ if (LCV) {
+ QualType RegionTy = R->getValueType();
+ QualType SourceRegionTy = LCV->getRegion()->getValueType();
+ if (RegionTy.getCanonicalType() == SourceRegionTy.getCanonicalType())
+ return *LCV;
+ }
+ }
+
+ return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
- const TypedValueRegion* R) {
+ const TypedValueRegion *R) {
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)) {
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(B.lookup(K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
+ return createLazyBinding(B, R);
}
SVal RegionStoreManager::getBindingForArray(RegionBindingsConstRef B,
- const TypedValueRegion * R) {
- const ConstantArrayType *Ty = Ctx.getAsConstantArrayType(R->getValueType());
- assert(Ty && "Only constant array types can have compound bindings.");
+ const TypedValueRegion *R) {
+ assert(Ctx.getAsConstantArrayType(R->getValueType()) &&
+ "Only constant array types can have compound bindings.");
- // 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())) {
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(B.lookup(K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
+ return createLazyBinding(B, R);
}
bool RegionStoreManager::includedInBindings(Store store,
test13116945(r.center); // no-warning
}
+
+typedef struct {
+ char data[4];
+} ShortString;
+
+typedef struct {
+ ShortString str;
+ int length;
+} ShortStringWrapper;
+
+void testArrayStructCopy() {
+ ShortString s = { "abc" };
+ ShortString s2 = s;
+ ShortString s3 = s2;
+
+ clang_analyzer_eval(s3.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s3.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s3.data[2] == 'c'); // expected-warning{{TRUE}}
+}
+
+void testArrayStructCopyNested() {
+ ShortString s = { "abc" };
+ ShortString s2 = s;
+
+ ShortStringWrapper w = { s2, 0 };
+
+ clang_analyzer_eval(w.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.length == 0); // expected-warning{{TRUE}}
+
+ ShortStringWrapper w2 = w;
+ clang_analyzer_eval(w2.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.length == 0); // expected-warning{{TRUE}}
+
+ ShortStringWrapper w3 = w2;
+ clang_analyzer_eval(w3.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.length == 0); // expected-warning{{TRUE}}
+}
+
// --------------------
// False positives
// --------------------