diff options
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 17 | ||||
-rw-r--r-- | clang/test/CodeGen/object-size.c | 25 | ||||
-rw-r--r-- | clang/test/CodeGen/pass-object-size.c | 9 |
3 files changed, 40 insertions, 11 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 107913ed61b..15b554bf27a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6826,14 +6826,21 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, // struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar)); // strcpy(&F->c[0], Bar); // - // So, if we see that we're examining a 1-length (or 0-length) array at the - // end of a struct with an unknown base, we give up instead of breaking code - // that behaves this way. Note that we only do this when Type=1, because - // Type=3 is a lower bound, so answering conservatively is fine. + // So, if we see that we're examining an array at the end of a struct with an + // unknown base, we give up instead of breaking code that behaves this way. + // Note that we only do this when Type=1, because Type=3 is a lower bound, so + // answering conservatively is fine. + // + // We used to be a bit more aggressive here; we'd only be conservative if the + // array at the end was flexible, or if it had 0 or 1 elements. This broke + // some common standard library extensions (PR30346), but was otherwise + // seemingly fine. It may be useful to reintroduce this behavior with some + // sort of whitelist. OTOH, it seems that GCC is always conservative with the + // last element in structs (if it's an array), so our current behavior is more + // compatible than a whitelisting approach would be. if (End.InvalidBase && SubobjectOnly && Type == 1 && End.Designator.Entries.size() == End.Designator.MostDerivedPathLength && End.Designator.MostDerivedIsArrayElement && - End.Designator.MostDerivedArraySize < 2 && isDesignatorAtObjectEnd(Info.Ctx, End)) return false; diff --git a/clang/test/CodeGen/object-size.c b/clang/test/CodeGen/object-size.c index 6aee57375a4..a3f3bce9295 100644 --- a/clang/test/CodeGen/object-size.c +++ b/clang/test/CodeGen/object-size.c @@ -276,7 +276,7 @@ void test23(struct Test23Ty *p) { // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(&p->t[5], 0); - // CHECK: store i32 20 + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(&p->t[5], 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) gi = __builtin_object_size(&p->t[5], 2); @@ -444,7 +444,7 @@ void test29(struct DynStructVar *dv, struct DynStruct0 *d0, // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(ss->snd, 0); - // CHECK: store i32 2 + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(ss->snd, 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) gi = __builtin_object_size(ss->snd, 2); @@ -505,7 +505,7 @@ void test31() { // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(ds1[9].snd, 1); - // CHECK: store i32 2 + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(&ss[9].snd[0], 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) @@ -517,3 +517,22 @@ void test31() { // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(&dsv[9].snd[0], 1); } + +// CHECK-LABEL: @PR30346 +void PR30346() { + struct sa_family_t {}; + struct sockaddr { + struct sa_family_t sa_family; + char sa_data[14]; + }; + + struct sockaddr *sa; + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + gi = __builtin_object_size(sa->sa_data, 0); + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + gi = __builtin_object_size(sa->sa_data, 1); + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) + gi = __builtin_object_size(sa->sa_data, 2); + // CHECK: store i32 14 + gi = __builtin_object_size(sa->sa_data, 3); +} diff --git a/clang/test/CodeGen/pass-object-size.c b/clang/test/CodeGen/pass-object-size.c index 6e2bc2090ed..6f5827befa7 100644 --- a/clang/test/CodeGen/pass-object-size.c +++ b/clang/test/CodeGen/pass-object-size.c @@ -59,7 +59,8 @@ void test1() { // CHECK-LABEL: define void @test2 void test2(struct Foo *t) { - // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36) + // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]]) gi = ObjectSize1(&t->t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36) gi = ObjectSize3(&t->t[1]); @@ -168,7 +169,8 @@ void test4(struct Foo *t) { // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize0(&t[1].t[1]); - // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36) + // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]]) gi = NoViableOverloadObjectSize1(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize2(&t[1].t[1]); @@ -274,7 +276,8 @@ void test7() { // CHECK-LABEL: define void @test8 void test8(struct Foo *t) { - // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) + // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]]) gi = AsmObjectSize1(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize3(&t[1].t[1]); |