]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Do not apply properties to arch-allocated types
authorTom Tromey <tromey@adacore.com>
Thu, 6 Nov 2025 15:06:33 +0000 (08:06 -0700)
committerTom Tromey <tromey@adacore.com>
Thu, 20 Nov 2025 16:14:34 +0000 (09:14 -0700)
A user reported that gdb would crash when debugging a certain Fortran
executable.

The bug is that the DWARF reader may try to apply dynamic properties
to an arch-allocated type.  This came as a bit of a surprise, but the
issue is that the function-type-allocation code could end up creating
an arch-owned type, when the return type is arch-owned.

This patch fixes the problem, and any other potential future problems,
by arranging for all types created by the DWARF reader to be
objfile-owned.

A better long-term solution might be the fabled "type GC", where the
arch/objfile distinction is finally removed.  However, this is more
difficult to implement.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32793

gdb/dwarf2/cu.c
gdb/dwarf2/read.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/testsuite/gdb.dwarf2/builtin-type-copy.exp [new file with mode: 0644]

index 86b77f5951ef2d794f825c94ad6cf799e4d4e8f5..b3851512f8956f5278665830219d40afd9341496 100644 (file)
@@ -60,7 +60,10 @@ struct type *
 dwarf2_cu::addr_sized_int_type (bool unsigned_p) const
 {
   int addr_size = this->per_cu->addr_size ();
-  return objfile_int_type (this->per_objfile->objfile, addr_size, unsigned_p);
+  struct type *result = objfile_int_type (this->per_objfile->objfile,
+                                         addr_size, unsigned_p);
+  type_allocator alloc (per_objfile->objfile, lang ());
+  return alloc.copy_type (result);
 }
 
 /* Start a symtab for DWARF.  NAME, COMP_DIR, LOW_PC are passed to the
index 8bc98342db8fa49d819405728e7c2c679c3ef7ed..0e8dc5dd46c0af201a85dad6b370d42e24fed027 100644 (file)
@@ -12232,8 +12232,8 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
      arrays with unspecified length.  */
   if (die->child == NULL)
     {
-      index_type = builtin_type (objfile)->builtin_int;
       type_allocator alloc (objfile, cu->lang ());
+      index_type = alloc.copy_type (builtin_type (objfile)->builtin_int);
       range_type = create_static_range_type (alloc, index_type, 0, -1);
       type = create_array_type_with_stride (alloc, element_type, range_type,
                                            byte_stride_prop, bit_stride);
@@ -12577,7 +12577,9 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu)
            }
        }
 
-      sym = new_symbol (die, builtin_type (objfile)->builtin_void, cu);
+      type_allocator alloc (objfile, cu->lang ());
+      type *void_type = alloc.copy_type (builtin_type (objfile)->builtin_void);
+      sym = new_symbol (die, void_type, cu);
       sym->set_value_common_block (common_block);
     }
 }
@@ -13124,6 +13126,8 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
        {
          LONGEST sz = len->unsigned_constant ().value_or (0);
          prop_type = objfile_int_type (objfile, sz, true);
+         type_allocator alloc (objfile, cu->lang ());
+         prop_type = alloc.copy_type (prop_type);
        }
       else
        {
@@ -13156,8 +13160,8 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
       length = 1;
     }
 
-  index_type = builtin_type (objfile)->builtin_int;
   type_allocator alloc (objfile, cu->lang ());
+  index_type = alloc.copy_type (builtin_type (objfile)->builtin_int);
   if (length_is_constant)
     range_type = create_static_range_type (alloc, index_type, 1, length);
   else
@@ -13279,7 +13283,9 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
 
   if (die->child != NULL)
     {
-      struct type *void_type = builtin_type (objfile)->builtin_void;
+      type_allocator alloc (objfile, cu->lang ());
+      struct type *void_type
+       = alloc.copy_type (builtin_type (objfile)->builtin_void);
       int nparams, iparams;
 
       /* Count the number of parameters.
@@ -13726,14 +13732,12 @@ dwarf2_init_integer_type (struct dwarf2_cu *cu, int bits, int unsigned_p,
   /* Versions of Intel's C Compiler generate an integer type called "void"
      instead of using DW_TAG_unspecified_type.  This has been seen on
      at least versions 14, 17, and 18.  */
+  type_allocator alloc (objfile, cu->lang ());
   if (bits == 0 && cu->producer_is_icc () && name != nullptr
       && strcmp (name, "void") == 0)
-    type = builtin_type (objfile)->builtin_void;
+    type = alloc.copy_type (builtin_type (objfile)->builtin_void);
   else
-    {
-      type_allocator alloc (objfile, cu->lang ());
-      type = init_integer_type (alloc, bits, unsigned_p, name);
-    }
+    type = init_integer_type (alloc, bits, unsigned_p, name);
 
   return type;
 }
@@ -16225,19 +16229,24 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
       switch (die->tag)
        {
        case DW_TAG_label:
-         attr = dwarf2_attr (die, DW_AT_low_pc, cu);
-         if (attr != nullptr)
-           {
-             CORE_ADDR addr = per_objfile->relocate (attr->as_address ());
-             sym->set_section_index (SECT_OFF_TEXT (objfile));
-             sym->set_value_address (addr);
-             sym->set_loc_class_index (LOC_LABEL);
-           }
-         else
-           sym->set_loc_class_index (LOC_OPTIMIZED_OUT);
-         sym->set_type (builtin_type (objfile)->builtin_core_addr);
-         sym->set_domain (LABEL_DOMAIN);
-         list_to_add = cu->list_in_scope;
+         {
+           attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+           if (attr != nullptr)
+             {
+               CORE_ADDR addr = per_objfile->relocate (attr->as_address ());
+               sym->set_section_index (SECT_OFF_TEXT (objfile));
+               sym->set_value_address (addr);
+               sym->set_loc_class_index (LOC_LABEL);
+             }
+           else
+             sym->set_loc_class_index (LOC_OPTIMIZED_OUT);
+           type_allocator alloc (objfile, cu->lang ());
+           struct type *addr_type
+             = alloc.copy_type (builtin_type (objfile)->builtin_core_addr);
+           sym->set_type (addr_type);
+           sym->set_domain (LABEL_DOMAIN);
+           list_to_add = cu->list_in_scope;
+         }
          break;
        case DW_TAG_entry_point:
          /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
@@ -16318,7 +16327,12 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
             variables with missing type entries.  Change the
             misleading `void' type to something sensible.  */
          if (sym->type ()->code () == TYPE_CODE_VOID)
-           sym->set_type (builtin_type (objfile)->builtin_int);
+           {
+             type_allocator alloc (objfile, cu->lang ());
+             struct type *int_type
+               = alloc.copy_type (builtin_type (objfile)->builtin_int);
+             sym->set_type (int_type);
+           }
 
          attr = dwarf2_attr (die, DW_AT_const_value, cu);
          /* In the case of DW_TAG_member, we should only be called for
@@ -16777,7 +16791,8 @@ die_type (struct die_info *die, struct dwarf2_cu *cu)
     {
       struct objfile *objfile = cu->per_objfile->objfile;
       /* A missing DW_AT_type represents a void type.  */
-      return builtin_type (objfile)->builtin_void;
+      type_allocator alloc (objfile, cu->lang ());
+      return alloc.copy_type (builtin_type (objfile)->builtin_void);
     }
 
   return lookup_die_type (die, type_attr, cu);
index 63d6f4c0ceb68436211970365bd116bf0329afb9..9e3c07e0ee59e4813fb70705fbffb0a6299aa88f 100644 (file)
@@ -5673,28 +5673,42 @@ copy_type_recursive (struct type *type, copied_types_hash_t &copied_types)
   return new_type;
 }
 
-/* Make a copy of the given TYPE, except that the pointer & reference
-   types are not preserved.  */
+/* See gdbtypes.h.  */
 
 struct type *
-copy_type (const struct type *type)
+type_allocator::copy_type (const struct type *type)
 {
-  struct type *new_type = type_allocator (type).new_type ();
+  struct type *new_type = this->new_type ();
   new_type->set_instance_flags (type->instance_flags ());
   new_type->set_length (type->length ());
   memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type),
          sizeof (struct main_type));
+
+  /* This might have been overwritten by the memcpy.  */
+  if (m_is_objfile)
+    new_type->set_owner (m_data.objfile);
+  else
+    new_type->set_owner (m_data.gdbarch);
+
   if (type->main_type->dyn_prop_list != NULL)
     {
-      struct obstack *storage = (type->is_objfile_owned ()
-                                ? &type->objfile_owner ()->objfile_obstack
-                                : gdbarch_obstack (type->arch_owner ()));
+      struct obstack *storage = (new_type->is_objfile_owned ()
+                                ? &new_type->objfile_owner ()->objfile_obstack
+                                : gdbarch_obstack (new_type->arch_owner ()));
       new_type->main_type->dyn_prop_list
        = copy_dynamic_prop_list (storage, type->main_type->dyn_prop_list);
     }
 
   return new_type;
 }
+
+/* See gdbtypes.h.  */
+
+struct type *
+copy_type (const struct type *type)
+{
+  return type_allocator (type).copy_type (type);
+}
 \f
 /* Helper functions to initialize architecture-specific types.  */
 
index ccdc18fe372fd4b8871a21e5ebd729d109af21de..3ae5a1ef4841bca46897eafdc6784a9441523d1d 100644 (file)
@@ -2315,6 +2315,11 @@ public:
      if type-smashing was selected at construction.  */
   type *new_type (enum type_code code, int bit, const char *name);
 
+  /* Create a copy of TYPE on the desired obstack.  This is
+     incompatible with the "SMASH" kind; this is verified using an
+     assert.  */
+  type *copy_type (const type *type);
+
   /* Return the architecture associated with this allocator.  This
      comes from whatever object was supplied to the constructor.  */
   gdbarch *arch ();
@@ -2839,6 +2844,10 @@ using copied_types_hash_t = gdb::unordered_map<type *, type *>;
 extern struct type *copy_type_recursive (struct type *type,
                                         copied_types_hash_t &copied_types);
 
+/* Make a copy of the given TYPE, except that the pointer & reference
+   types are not preserved.  The new type is allocated using the same
+   storage as TYPE.  */
+
 extern struct type *copy_type (const struct type *type);
 
 extern bool types_equal (struct type *, struct type *);
diff --git a/gdb/testsuite/gdb.dwarf2/builtin-type-copy.exp b/gdb/testsuite/gdb.dwarf2/builtin-type-copy.exp
new file mode 100644 (file)
index 0000000..b1890c7
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+require dwarf2_support
+
+standard_testfile main.c -dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+       DW_TAG_compile_unit {
+               DW_AT_language @DW_LANG_Fortran90
+               DW_AT_name     hello.f90
+               DW_AT_comp_dir /tmp
+       } {
+           declare_labels integer_label subr_label pointer_label
+
+           integer_label: DW_TAG_base_type {
+               DW_AT_byte_size 4 DW_FORM_sdata
+               DW_AT_encoding @DW_ATE_signed
+               DW_AT_name integer
+           }
+
+           subr_label: DW_TAG_subroutine_type {
+               DW_AT_decl_line 55 DW_FORM_data1
+               DW_AT_decl_file 1 DW_FORM_data1
+               DW_AT_name GAMSRESULTSLOADER DW_FORM_strp
+           } {
+               DW_TAG_formal_parameter {
+                   DW_AT_type :$integer_label
+               }
+           }
+
+           pointer_label: DW_TAG_pointer_type {
+               DW_AT_type :$subr_label
+               # The contents here don't really matter.
+               DW_AT_associated {
+                   DW_OP_lit8
+               } SPECIAL_expr
+           }
+
+           DW_TAG_typedef {
+               DW_AT_name pointer
+               DW_AT_type :$pointer_label
+           }
+       }
+    }
+}
+
+# Now that we've generated the DWARF debugging info, rebuild our
+# program using our debug info instead of the info generated by
+# the compiler.
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+         [list $srcfile $asm_file] {nodebug}] } {
+    return
+}
+
+# The bug was that the DWARF reader would try to add a property to an
+# arch-owned type, triggering a crash.  So simply expanding the
+# symtabs would cause this.
+gdb_test_no_output "maint expand-symtabs"