diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 915c9b0cf1014..a124617fac8bb 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -51,6 +51,11 @@ C/C++ Language Potentially Breaking Changes foo: asm goto ("# %0 %1"::"i"(&&foo)::foo); +- ``__builtin_object_size`` and ``__builtin_dynamic_object_size`` now add the + ``sizeof`` the elements specified in designated initializers of flexible + array members for structs that contain them. This change is more consistent + with the behavior of GCC. + C++ Specific Potentially Breaking Changes ----------------------------------------- - Clang won't search for coroutine_traits in std::experimental namespace any more. @@ -424,6 +429,10 @@ Bug Fixes in This Version (`#61746 `_). - Clang `TextNodeDumper` enabled through `-ast-dump` flag no longer evaluates the initializer of constexpr `VarDecl` if the declaration has a dependent type. +- Match GCC's behavior for ``__builtin_object_size`` and + ``__builtin_dynamic_object_size`` on structs containing flexible array + members. + (`#62789 `_). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 423ed86ef41e2..d88f9535c1a4b 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11721,6 +11721,18 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int, return true; } +/// If we're evaluating the object size of an instance of a struct that +/// contains a flexible array member, add the size of the initializer. +static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T, + const LValue &LV, CharUnits &Size) { + if (!T.isNull() && T->isStructureType() && + T->getAsStructureType()->getDecl()->hasFlexibleArrayMember()) + if (const auto *V = LV.getLValueBase().dyn_cast()) + if (const auto *VD = dyn_cast(V)) + if (VD->hasInit()) + Size += VD->getFlexibleArrayInitChars(Info.Ctx); +} + /// Helper for tryEvaluateBuiltinObjectSize -- Given an LValue, this will /// determine how many bytes exist from the beginning of the object to either /// the end of the current subobject, or the end of the object itself, depending @@ -11755,7 +11767,9 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, return false; QualType BaseTy = getObjectType(LVal.getLValueBase()); - return CheckedHandleSizeof(BaseTy, EndOffset); + const bool Ret = CheckedHandleSizeof(BaseTy, EndOffset); + addFlexibleArrayMemberInitSize(Info, BaseTy, LVal, EndOffset); + return Ret; } // We want to evaluate the size of a subobject. diff --git a/clang/test/CodeGen/object-size.c b/clang/test/CodeGen/object-size.c index 157926dd719d6..b39b15fcc65b9 100644 --- a/clang/test/CodeGen/object-size.c +++ b/clang/test/CodeGen/object-size.c @@ -525,6 +525,52 @@ void test31(void) { gi = OBJECT_SIZE_BUILTIN(&dsv[9].snd[0], 1); } +// CHECK-LABEL: @test32 +static struct DynStructVar D32 = { + .fst = {}, + .snd = { 0, 1, 2, }, +}; +unsigned long test32(void) { + // CHECK: ret i64 19 + return OBJECT_SIZE_BUILTIN(&D32, 1); +} +// CHECK-LABEL: @test33 +static struct DynStructVar D33 = { + .fst = {}, + .snd = {}, +}; +unsigned long test33(void) { + // CHECK: ret i64 16 + return OBJECT_SIZE_BUILTIN(&D33, 1); +} +// CHECK-LABEL: @test34 +static struct DynStructVar D34 = { + .fst = {}, +}; +unsigned long test34(void) { + // CHECK: ret i64 16 + return OBJECT_SIZE_BUILTIN(&D34, 1); +} +// CHECK-LABEL: @test35 +unsigned long test35(void) { + // CHECK: ret i64 16 + return OBJECT_SIZE_BUILTIN(&(struct DynStructVar){}, 1); +} +extern void *memset (void *s, int c, unsigned long n); +void test36(void) { + struct DynStructVar D; + // FORTIFY will check the object size of D. Test this doesn't assert when + // given a struct with a flexible array member that lacks an initializer. + memset(&D, 0, sizeof(D)); +} +// CHECK-LABEL: @test37 +struct Z { struct A { int x, y[]; } z; int a; int b[]; }; +static struct Z my_z = { .b = {1,2,3} }; +unsigned long test37 (void) { + // CHECK: ret i64 4 + return OBJECT_SIZE_BUILTIN(&my_z.z, 1); +} + // CHECK-LABEL: @PR30346 void PR30346(void) { struct sa_family_t {};