]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: resolve dynamic type in one value_cast case
authorSimon Marchi <simon.marchi@efficios.com>
Tue, 18 Nov 2025 03:38:25 +0000 (22:38 -0500)
committerSimon Marchi <simon.marchi@polymtl.ca>
Mon, 24 Nov 2025 04:39:53 +0000 (23:39 -0500)
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 <tom@tromey.com>
gdb/testsuite/gdb.dwarf2/data-loc-cast.exp
gdb/valops.c

index 3a420eb3f3c6269d78c325117724b025e3c80e7f..5b4977529d8036f3a1086638e20c40a23df21630 100644 (file)
@@ -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" " = <not associated>"
 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 = <not associated> \\)"
+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" " = <not associated>"
+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 \\(:\\)"
index 0be0288e6aad602fd0336a0ff2b9a6d9a5f18a06..21dac7aa59cc4b739aff43dd5dfb561559dbd503 100644 (file)
@@ -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;
     }