[clang] 804af93 - Reland: [clang][ExprConstant] fix __builtin_object_size for flexible array members

Nick Desaulniers via cfe-commits cfe-commits at lists.llvm.org
Tue May 23 14:51:29 PDT 2023


Author: Nick Desaulniers
Date: 2023-05-23T14:41:46-07:00
New Revision: 804af933f7310f78d91e13ad8a13b64b00249614

URL: https://github.com/llvm/llvm-project/commit/804af933f7310f78d91e13ad8a13b64b00249614
DIFF: https://github.com/llvm/llvm-project/commit/804af933f7310f78d91e13ad8a13b64b00249614.diff

LOG: Reland: [clang][ExprConstant] fix __builtin_object_size for flexible array members

As reported by @kees, GCC treats __builtin_object_size of structures
containing flexible array members (aka arrays with incomplete type) not
just as the sizeof the underlying type, but additionally the size of the
members in a designated initializer list.

Fixes: https://github.com/llvm/llvm-project/issues/62789

Reviewed By: erichkeane, efriedma

Differential Revision: https://reviews.llvm.org/D150892

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ExprConstant.cpp
    clang/test/CodeGen/object-size.c

Removed: 
    


################################################################################
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 <https://github.com/llvm/llvm-project/issues/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 <https://github.com/llvm/llvm-project/issues/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<const ValueDecl *>())
+      if (const auto *VD = dyn_cast<VarDecl>(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 {};


        


More information about the cfe-commits mailing list