https://gcc.gnu.org/g:50efa788a4b6c7f619101b6156b47b91124c6dd3

commit r16-3723-g50efa788a4b6c7f619101b6156b47b91124c6dd3
Author: David Faust <[email protected]>
Date:   Thu Aug 28 09:12:55 2025 -0700

    ctf: fix integer truncations in very large structs [PR121411]
    
    DWARF to CTF translation for type bit sizes was using uint32_t, and for
    member offsets was inadvertently using unsigned int via get_AT_unsigned.
    For very large struct types, at least one of these could be truncated
    causing incorrect encoding of the struct type and member offsets.
    
    Use HOST_WIDE_INT to avoid these truncation issues and fix the encoding
    for large structs.
    
            PR debug/121411
    
    gcc/
    
            * dwarf2ctf.cc (ctf_get_AT_data_member_location) Use AT_unsigned
            when fetching AT_bit_offset and AT_data_member_location.  Simplify.
            (ctf_die_bitsize): Return unsigned HOST_WIDE_INT instead of
            uint32_t.
            (gen_ctf_base_type, gen_ctf_sou_type, gen_ctf_enumeration_type):
            Adapt accordingly.
    
    gcc/testsuite/
    
            * gcc.dg/debug/ctf/ctf-struct-3.c: New test.

Diff:
---
 gcc/dwarf2ctf.cc                              | 34 +++++++++++++--------------
 gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c | 32 +++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index f8b305b6c4a8..4b49b23f0780 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -87,8 +87,8 @@ ctf_get_AT_data_member_location (dw_die_ref die)
   /* The field location (in bits) can be determined from
      either a DW_AT_data_member_location attribute or a
      DW_AT_data_bit_offset attribute.  */
-  if (get_AT (die, DW_AT_data_bit_offset))
-    field_location = get_AT_unsigned (die, DW_AT_data_bit_offset);
+  if ((attr = get_AT (die, DW_AT_data_bit_offset)))
+    field_location = AT_unsigned (attr);
   else
     {
       attr = get_AT (die, DW_AT_data_member_location);
@@ -102,16 +102,12 @@ ctf_get_AT_data_member_location (dw_die_ref die)
                      == dw_val_class_unsigned_const);
          field_location = descr->dw_loc_oprnd1.v.val_unsigned * 8;
        }
-      else
-       {
-         attr = get_AT (die, DW_AT_data_member_location);
-         if (attr && AT_class (attr) == dw_val_class_const)
-           field_location = AT_int (attr) * 8;
-         else
-           field_location = (get_AT_unsigned (die,
-                                          DW_AT_data_member_location)
-                             * 8);
-       }
+      else if (attr && AT_class (attr) == dw_val_class_const)
+       field_location = AT_int (attr) * 8;
+      else if (attr)
+       field_location = AT_unsigned (attr) * 8;
+
+      /* Otherwise the location is non-existant, e.g. for union members.  */
     }
 
   return field_location;
@@ -199,7 +195,7 @@ gen_ctf_unknown_type (ctf_container_ref ctfc)
    If no DW_AT_byte_size nor DW_AT_bit_size are defined, this function
    returns 0.  */
 
-static uint32_t
+static unsigned HOST_WIDE_INT
 ctf_die_bitsize (dw_die_ref die)
 {
   dw_attr_node *attr_byte_size = get_AT (die, DW_AT_byte_size);
@@ -225,7 +221,9 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
   ctf_encoding_t ctf_encoding = {0, 0, 0};
 
   unsigned int encoding = get_AT_unsigned (type, DW_AT_encoding);
-  unsigned int bit_size = ctf_die_bitsize (type);
+  /* Bit size for the base types handled here should never be extremely large
+     (BITSIZE_MAXWIDTH at the upper end for _BitInt).  */
+  unsigned int bit_size = (unsigned int) ctf_die_bitsize (type);
   const char * name_string = get_AT_string (type, DW_AT_name);
 
   switch (encoding)
@@ -514,7 +512,7 @@ gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref 
modifier)
 static ctf_dtdef_ref
 gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
 {
-  uint32_t bit_size = ctf_die_bitsize (sou);
+  unsigned HOST_WIDE_INT bit_size = ctf_die_bitsize (sou);
   int declaration_p = get_AT_flag (sou, DW_AT_declaration);
   const char *sou_name = get_AT_string (sou, DW_AT_name);
 
@@ -564,7 +562,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, 
uint32_t kind)
            {
              dw_attr_node *attr;
              HOST_WIDE_INT bitpos = 0;
-             HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
+             unsigned HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
              HOST_WIDE_INT bit_offset;
 
              /* The bit offset is given in bits and it may be
@@ -581,7 +579,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, 
uint32_t kind)
                    bitpos = field_location + bit_offset;
                  else
                    {
-                     HOST_WIDE_INT bit_size;
+                     unsigned HOST_WIDE_INT bit_size;
 
                      attr = get_AT (c, DW_AT_byte_size);
                      if (attr)
@@ -730,7 +728,7 @@ static ctf_dtdef_ref
 gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
 {
   const char *enum_name = get_AT_string (enumeration, DW_AT_name);
-  unsigned int bit_size = ctf_die_bitsize (enumeration);
+  unsigned HOST_WIDE_INT bit_size = ctf_die_bitsize (enumeration);
   unsigned int signedness = get_AT_unsigned (enumeration, DW_AT_encoding);
   int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
 
diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c 
b/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
new file mode 100644
index 000000000000..bf0be87c7c94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
@@ -0,0 +1,32 @@
+/* PR debug/121411.
+   Test for compilation of very large struct types.
+   The ctt_size for the struct shall encode CTF_LSIZE_SENT to indicate the
+   large struct encoding is used.  */
+
+/* { dg-do compile { target { lp64 || llp64 } } } */
+/* { dg-options "-O0 -gctf -dA" } */
+
+struct huge
+{                               /* bit offset  */
+  unsigned char a1[0xffffffff]; /*          0  */
+  unsigned char a2[0xffffffff]; /*  7fffffff8  */
+  char x;                       /*  ffffffff0  */
+  char y;                       /*  ffffffff8  */
+  char z;                       /* 1000000000  */
+};
+
+struct huge v;
+
+/* Verify struct is encoded with large type encoding format.  */
+/* { dg-final { scan-assembler-times "0x1a000005\[\t \]+\[^\n\]*ctt_info" 1 } 
} */
+/* { dg-final { scan-assembler-times "0xffffffff\[\t \]+\[^\n\]*ctt_size" 1 } 
} */
+/* { dg-final { scan-assembler-times "0x2\[\t \]+\[^\n\]*ctt_lsizehi" 1 } } */
+/* { dg-final { scan-assembler-times "ctt_lsizelo" 1 } } */
+
+/* Verify member offsets are correct for large offsets.  */
+/* { dg-final { scan-assembler-times "0x7\[\t \]+\[^\n\]*ctlm_offsethi" 1 } } 
*/
+/* { dg-final { scan-assembler-times "0xf\[\t \]+\[^\n\]*ctlm_offsethi" 2 } } 
*/
+/* { dg-final { scan-assembler-times "0x10\[\t \]+\[^\n\]*ctlm_offsethi" 1 } } 
*/
+
+/* { dg-final { scan-assembler-times "0xfffffff8\[\t \]+\[^\n\]*ctlm_offsetlo" 
2 } } */
+/* { dg-final { scan-assembler-times "0xfffffff0\[\t \]+\[^\n\]*ctlm_offsetlo" 
1 } } */

Reply via email to