]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ctf: fix integer truncations in very large structs [PR121411]
authorDavid Faust <david.faust@oracle.com>
Thu, 28 Aug 2025 16:12:55 +0000 (09:12 -0700)
committerDavid Faust <david.faust@oracle.com>
Tue, 9 Sep 2025 15:56:54 +0000 (08:56 -0700)
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.

gcc/dwarf2ctf.cc
gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c [new file with mode: 0644]

index f8b305b6c4a8377409c093adcaf47b5aa88be668..4b49b23f0780578e82ef11fc338b1446de5146a6 100644 (file)
@@ -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 (file)
index 0000000..bf0be87
--- /dev/null
@@ -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 } } */