[PATCH v2] gdb: Check DW_OP_deref_type size against type

Jielun Wu <[email protected]>
Newsgroups gmane.comp.gdb.patches
Message-ID <[email protected]>
DWARF v5 requires the explicit size operand of DW_OP_deref_type to
match the size of the referenced base type.  The evaluator currently
passes both sizes to dwarf_expr_context::deref without validating the
encoding, and the generic dereference helper accepts the mismatch by
zero-extending the bytes read from memory.

Reject a mismatch after resolving the base type.  Name the actual opcode
and report both sizes in the diagnostic.

Teach the testsuite's DWARF assembler to emit DW_OP_deref_type and
DW_OP_GNU_deref_type operands.  Add tests covering matching and
mismatched sizes for both opcodes.

Tested on x86_64-linux.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34277
Signed-off-by: Jielun Wu <[email protected]>
---
Changes in v2:
- Name the actual opcode and report both sizes in the diagnostic.
- Rename addr_size to deref_size.
- Add DWARF assembler handlers for the standard and GNU opcodes.
- Add matching-size coverage for both opcodes.

 gdb/dwarf2/expr.c                             | 10 ++-
 .../gdb.dwarf2/dw2-deref-type-size.c          | 22 +++++
 .../gdb.dwarf2/dw2-deref-type-size.exp        | 88 +++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp                   | 11 +++
 4 files changed, 129 insertions(+), 2 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.exp

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 3a6b8f58199..7160a73d80b 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2016,7 +2016,8 @@ dwarf_expr_context::execute_stack_op (gdb::array_view<const gdb_byte> expr)
 	case DW_OP_deref_type:
 	case DW_OP_GNU_deref_type:
 	  {
-	    int addr_size = (op == DW_OP_deref ? this->m_addr_size : *op_ptr++);
+	    int deref_size
+	      = (op == DW_OP_deref ? this->m_addr_size : *op_ptr++);
 	    CORE_ADDR addr = fetch_address (0);
 	    struct type *type;
 
@@ -2027,11 +2028,16 @@ dwarf_expr_context::execute_stack_op (gdb::array_view<const gdb_byte> expr)
 		op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
 		cu_offset type_die_cu_off = (cu_offset) uoffset;
 		type = get_base_type (type_die_cu_off);
+		if (type->length () != deref_size)
+		  error (_("%s has dereference size %d, but its "
+			   "type has size %s"),
+			 get_DW_OP_name (op), deref_size,
+			 pulongest (type->length ()));
 	      }
 	    else
 	      type = address_type;
 
-	    result_val = this->deref (addr, addr_size, type);
+	    result_val = this->deref (addr, deref_size, type);
 	    break;
 	  }
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.c b/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.c
new file mode 100644
index 00000000000..af01073cd74
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.c
@@ -0,0 +1,22 @@
+/* Copyright 2026 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/>.  */
+
+unsigned char deref_data = 0x5a;
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.exp b/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.exp
new file mode 100644
index 00000000000..82d369f5220
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-deref-type-size.exp
@@ -0,0 +1,88 @@
+# Copyright 2026 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/>.
+
+# Test DW_OP_deref_type with explicit dereference sizes that both match
+# and differ from the size of the referenced base type.
+
+load_lib dwarf.exp
+
+require dwarf2_support
+
+standard_testfile .c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+
+Dwarf::assemble $asm_file {
+    cu {version 5} {
+	compile_unit {} {
+	    declare_labels uint8_label uint64_label
+
+	    uint8_label: base_type {
+		DW_AT_name "uint8_t"
+		DW_AT_encoding @DW_ATE_unsigned_char
+		DW_AT_byte_size 1 DW_FORM_sdata
+	    }
+
+	    uint64_label: base_type {
+		DW_AT_name "uint64_t"
+		DW_AT_encoding @DW_ATE_unsigned
+		DW_AT_byte_size 8 DW_FORM_sdata
+	    }
+
+	    foreach {var op size type_label} [list \
+		valid_deref_type DW_OP_deref_type 1 $uint8_label \
+		valid_gnu_deref_type DW_OP_GNU_deref_type 1 $uint8_label \
+		invalid_deref_type DW_OP_deref_type 4 $uint64_label \
+		invalid_gnu_deref_type DW_OP_GNU_deref_type 4 $uint64_label] {
+		DW_TAG_variable {
+		    DW_AT_name $var
+		    DW_AT_type :$type_label
+		    DW_AT_external 1 DW_FORM_flag
+		    DW_AT_location {
+			DW_OP_addr [gdb_target_symbol "deref_data"]
+			$op $size $type_label
+			DW_OP_stack_value
+		    } SPECIAL_expr
+		}
+	    }
+	}
+    }
+}
+
+if {[prepare_for_testing "failed to prepare" ${testfile} \
+	 [list $srcfile $asm_file] nodebug]} {
+    return
+}
+
+if {![runto_main]} {
+    return
+}
+
+foreach_with_prefix var {
+    valid_deref_type
+    valid_gnu_deref_type
+} {
+    gdb_test "print/x $var" " = 0x5a"
+}
+
+foreach {var op} {
+    invalid_deref_type DW_OP_deref_type
+    invalid_gnu_deref_type DW_OP_GNU_deref_type
+} {
+    with_test_prefix $var {
+	gdb_test "print $var" \
+	    "$op has dereference size 4, but its type has size 8"
+    }
+}
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 839c5174265..54102b1981d 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -1460,6 +1460,17 @@ namespace eval Dwarf {
 	_op .byte $size
     }
 
+    proc _handle_DW_OP_deref_type {size label} {
+	variable _cu_label
+
+	_op .byte $size
+	_op .uleb128 "$label - $_cu_label"
+    }
+
+    proc _handle_DW_OP_GNU_deref_type {size label} {
+	_handle_DW_OP_deref_type $size $label
+    }
+
     proc _handle_DW_OP_bregx {register offset} {
 	_op .uleb128 $register
 	_op .sleb128 $offset
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.