From: Simon Marchi Date: Tue, 18 Nov 2025 03:38:25 +0000 (-0500) Subject: gdb: resolve dynamic type in one value_cast case X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e5ef00196e3a5e8667b342bc287fc63e31f3db75;p=thirdparty%2Fbinutils-gdb.git gdb: resolve dynamic type in one value_cast case This particular path for value_cast does not attempt to resolve a dynamic target type before assigning it to the new value. Having a value with a dynamic type that hasn't been resolved causes an assert later, when printing the value. For instance, running the added test without the fix yields: (gdb) p (outer_type) g_outer_as_char_array $7 = ( /home/smarchi/src/binutils-gdb/gdb/value.c:3111: internal-error: primitive_field: Assertion `type->dyn_prop (DYN_PROP_DATA_LOCATION)->is_constant ()' failed. This code path is taken when the value being cast has the same size as the target type, and no earlier more specific rule matched. Fix it by adding a call to resolve_dynamic_type before assigning the target type to the value. The test exercises this by defining a char array (`g_outer_as_char_array`) with the same size as `outer_type` in the DWARF info, then casting it to `outer_type`. Without the fix, this triggers the assertion when printing the result. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33575 Change-Id: I547da32bbd24462b779e76bceb6e0a87859188d1 Approved-By: Tom Tromey --- diff --git a/gdb/testsuite/gdb.dwarf2/data-loc-cast.exp b/gdb/testsuite/gdb.dwarf2/data-loc-cast.exp index 3a420eb3f3c..5b4977529d8 100644 --- a/gdb/testsuite/gdb.dwarf2/data-loc-cast.exp +++ b/gdb/testsuite/gdb.dwarf2/data-loc-cast.exp @@ -117,6 +117,26 @@ Dwarf::assemble $asm_file { DW_OP_addr [gdb_target_symbol g_outer_var] } SPECIAL_expr } + + # char[sizeof(outer_type)] + declare_labels char_array_type_label + char_array_type_label: DW_TAG_array_type { + DW_AT_type :$char_type_label + } { + DW_TAG_subrange_type { + DW_AT_type :$int_type_label + DW_AT_count $sizeof_outer_type DW_FORM_udata + } + } + + # A view over "g_outer", typed as a char buffer. + DW_TAG_variable { + DW_AT_name g_outer_as_char_array + DW_AT_type :$char_array_type_label + DW_AT_location { + DW_OP_addr [gdb_target_symbol g_outer_var] + } SPECIAL_expr + } } } } @@ -168,3 +188,12 @@ gdb_test "p ((outer_type) g_outer_var)%assoc" "= \\($one_to_one_hundred\\)" gdb_test "p ((outer_type) g_outer_var)%non_assoc" " = " gdb_test "ptype ((outer_type) g_outer_var)%assoc" " = uintptr_t \\(6:105\\)" gdb_test "ptype ((outer_type) g_outer_var)%non_assoc" " = uintptr_t \\(:\\)" + +# Cast to outer_type something with the same size as outer_type. The code path +# taken by this would miss resolving the dynamic type, causing an assert when +# trying to print the resulting value. +gdb_test "p (outer_type) g_outer_as_char_array" " = \\( assoc = \\($one_to_one_hundred\\), non_assoc = \\)" +gdb_test "p ((outer_type) g_outer_as_char_array)%assoc" "= \\($one_to_one_hundred\\)" +gdb_test "p ((outer_type) g_outer_as_char_array)%non_assoc" " = " +gdb_test "ptype ((outer_type) g_outer_as_char_array)%assoc" " = uintptr_t \\(6:105\\)" +gdb_test "ptype ((outer_type) g_outer_as_char_array)%non_assoc" " = uintptr_t \\(:\\)" diff --git a/gdb/valops.c b/gdb/valops.c index 0be0288e6aa..21dac7aa59c 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -636,8 +636,11 @@ value_cast (struct type *type, struct value *arg2) return value_cast_pointers (to_type, arg2, 0); arg2 = arg2->copy (); - arg2->deprecated_set_type (to_type); - arg2->set_enclosing_type (to_type); + + struct type *resolved_type + = resolve_dynamic_type (to_type, arg2->contents (), arg2->address ()); + arg2->deprecated_set_type (resolved_type); + arg2->set_enclosing_type (resolved_type); arg2->set_pointed_to_offset (0); /* pai: chk_val */ return arg2; }