From: Tom Tromey Date: Thu, 6 Nov 2025 15:06:33 +0000 (-0700) Subject: Do not apply properties to arch-allocated types X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=315ac9939f61668281c290b7a4c4404dbec77630;p=thirdparty%2Fbinutils-gdb.git Do not apply properties to arch-allocated types 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 --- diff --git a/gdb/dwarf2/cu.c b/gdb/dwarf2/cu.c index 86b77f5951e..b3851512f89 100644 --- a/gdb/dwarf2/cu.c +++ b/gdb/dwarf2/cu.c @@ -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 diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 8bc98342db8..0e8dc5dd46c 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -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); diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 63d6f4c0ceb..9e3c07e0ee5 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -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); +} /* Helper functions to initialize architecture-specific types. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index ccdc18fe372..3ae5a1ef484 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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; 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 index 00000000000..b1890c76ab1 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/builtin-type-copy.exp @@ -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 . +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"