]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ctf: avoid overflow for array num elements [PR121411]
authorDavid Faust <david.faust@oracle.com>
Wed, 6 Aug 2025 16:24:40 +0000 (09:24 -0700)
committerDavid Faust <david.faust@oracle.com>
Mon, 25 Aug 2025 19:01:17 +0000 (12:01 -0700)
CTF array encoding uses uint32 for number of elements.  This means there
is a hard upper limit on array types which the format can represent.

GCC internally was also using a uint32_t for this, which would overflow
when translating from DWARF for arrays with more than UINT32_MAX
elements.  Use an unsigned HOST_WIDE_INT instead to fetch the array
bound, and fall back to CTF_K_UNKNOWN if the array cannot be
represented in CTF.

PR debug/121411

gcc/

* dwarf2ctf.cc (gen_ctf_subrange_type): Use unsigned HWI for
array_num_elements.  Fallback to CTF_K_UNKNOWN if the array
type has too many elements for CTF to represent.

gcc/testsuite/

* gcc.dg/debug/ctf/ctf-array-7.c: New test.

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

index 7de3696a4d7fbde6274d879e68fa32a9056c24ae..f8b305b6c4a8377409c093adcaf47b5aa88be668 100644 (file)
@@ -361,7 +361,7 @@ gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_dtdef_ref array_elems_type,
 
   dw_attr_node *upper_bound_at;
   dw_die_ref array_index_type;
-  uint32_t array_num_elements;
+  unsigned HOST_WIDE_INT array_num_elements;
 
   if (dw_get_die_tag (c) == DW_TAG_subrange_type)
     {
@@ -376,9 +376,9 @@ gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_dtdef_ref array_elems_type,
       if (upper_bound_at
          && AT_class (upper_bound_at) == dw_val_class_unsigned_const)
        /* This is the upper bound index.  */
-       array_num_elements = get_AT_unsigned (c, DW_AT_upper_bound) + 1;
+       array_num_elements = AT_unsigned (get_AT (c, DW_AT_upper_bound)) + 1;
       else if (get_AT (c, DW_AT_count))
-       array_num_elements = get_AT_unsigned (c, DW_AT_count);
+       array_num_elements = AT_unsigned (get_AT (c, DW_AT_count));
       else
        {
          /* This is a VLA of some kind.  */
@@ -388,6 +388,12 @@ gen_ctf_subrange_type (ctf_container_ref ctfc, ctf_dtdef_ref array_elems_type,
   else
     gcc_unreachable ();
 
+  if (array_num_elements > UINT32_MAX)
+    {
+      /* The array cannot be encoded in CTF.  TBD_CTF_REPRESENTATION_LIMIT.  */
+      return gen_ctf_unknown_type (ctfc);
+    }
+
   /* Ok, mount and register the array type.  Note how the array
      type we register here is the type of the elements in
      subsequent "dimensions", if there are any.  */
diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-7.c b/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-7.c
new file mode 100644 (file)
index 0000000..01accc7
--- /dev/null
@@ -0,0 +1,23 @@
+/* CTF generation for array which cannot be encoded in CTF.
+
+   CTF encoding uses a uint32 for number of elements in an array which
+   means there is a hard upper limit on sizes of arrays which can be
+   represented.  Arrays with too many elements are encoded with
+   CTF_K_UNKNOWN to indicate that they cannot be represented.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gctf -dA" } */
+
+int   rep[0xffffffff];
+int unrep[0x100000000];
+
+/* One dimension can be represented, other cannot.
+   Result is a (representable) array with unknown element type.  */
+int unrepdim [0xab][0x100000007];
+
+/* Two CTF_K_ARRAY, one (shared) CTF_K_UNKNOWN.  */
+/* { dg-final { scan-assembler-times "0x12000000\[\t \]+\[^\n\]*ctt_info" 2 } } */
+/* { dg-final { scan-assembler-times "0x2000000\[\t \]+\[^\n\]*ctt_info" 1 } } */
+
+/* { dg-final { scan-assembler-times "\[\t \]+0xffffffff\[\t \]+\[^\n\]*cta_nelems" 1 } } */
+/* { dg-final { scan-assembler-times "\[\t \]+0xab\[\t \]+\[^\n\]*cta_nelems" 1 } } */