[PATCH] gdb: call check_typedef at beginning of dwarf_expr_context::fetch_result

Simon Marchi simon.marchi@polymtl.ca
Sun Jul 24 03:59:49 GMT 2022


Bug 29374 shows this crash:

    $ ./gdb -nx --data-directory=data-directory -q -batch -ex "catch throw" -ex r -ex bt a.out
    ...
    /home/simark/src/binutils-gdb/gdb/../gdbsupport/array-view.h:217: internal-error: copy: Assertion `dest.size () == src.size ()' failed.

The backtrace is:

    #0  internal_error (file=0x5555606504c0 "/home/simark/src/binutils-gdb/gdb/../gdbsupport/array-view.h", line=217, fmt=0x55556064b700 "%s: Assertion `%s' failed.") at /home/simark/src/binutils-gdb/gdbsupport/errors.cc:51
    #1  0x000055555d41c0bb in gdb::copy<unsigned char const, unsigned char> (src=..., dest=...) at /home/simark/src/binutils-gdb/gdb/../gdbsupport/array-view.h:217
    #2  0x000055555deef28c in dwarf_expr_context::fetch_result (this=0x7fffffffb830, type=0x621007a86830, subobj_type=0x621007a86830, subobj_offset=0, as_lval=false) at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1040
    #3  0x000055555def0015 in dwarf_expr_context::evaluate (this=0x7fffffffb830, addr=0x62f00004313e "0", len=1, as_lval=false, per_cu=0x60b000069550, frame=0x621007c9e910, addr_info=0x0, type=0x621007a86830, subobj_type=0x621007a86830, subobj_offset=0) at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1091
    #4  0x000055555e084327 in dwarf2_evaluate_loc_desc_full (type=0x621007a86830, frame=0x621007c9e910, data=0x62f00004313e "0", size=1, per_cu=0x60b000069550, per_objfile=0x613000006080, subobj_type=0x621007a86830, subobj_byte_offset=0, as_lval=false) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1485
    #5  0x000055555e0849e2 in dwarf2_evaluate_loc_desc (type=0x621007a86830, frame=0x621007c9e910, data=0x62f00004313e "0", size=1, per_cu=0x60b000069550, per_objfile=0x613000006080, as_lval=false) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1529
    #6  0x000055555e0828c6 in dwarf_entry_parameter_to_value (parameter=0x621007a96e58, deref_size=0x0, type=0x621007a86830, caller_frame=0x621007c9e910, per_cu=0x60b000069550, per_objfile=0x613000006080) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1235
    #7  0x000055555e082f55 in value_of_dwarf_reg_entry (type=0x621007a86890, frame=0x621007acc510, kind=CALL_SITE_PARAMETER_DWARF_REG, kind_u=...) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1332
    #8  0x000055555e083449 in value_of_dwarf_block_entry (type=0x621007a86890, frame=0x621007acc510, block=0x61e000033568 "T\004\205\001\240\004\004\243\001T\237\004\240\004\261\004\001T\004\261\004\304\005\004\243\001T\237\004\304\005\310\005\001T\004\310\005\311\005\004\243\001T\237", block_len=1) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1365
    #9  0x000055555e094d40 in loclist_read_variable_at_entry (symbol=0x621007a99bd0, frame=0x621007acc510) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:3889
    #10 0x000055555f5192e0 in read_frame_arg (fp_opts=..., sym=0x621007a99bd0, frame=0x621007acc510, argp=0x7fffffffbf20, entryargp=0x7fffffffbf60) at /home/simark/src/binutils-gdb/gdb/stack.c:559
    #11 0x000055555f51c352 in print_frame_args (fp_opts=..., func=0x621007a99ad0, frame=0x621007acc510, num=-1, stream=0x6030000bad90) at /home/simark/src/binutils-gdb/gdb/stack.c:887
    #12 0x000055555f521919 in print_frame (fp_opts=..., frame=0x621007acc510, print_level=1, print_what=LOCATION, print_args=1, sal=...) at /home/simark/src/binutils-gdb/gdb/stack.c:1390
    #13 0x000055555f51f22e in print_frame_info (fp_opts=..., frame=0x621007acc510, print_level=1, print_what=LOCATION, print_args=1, set_current_sal=0) at /home/simark/src/binutils-gdb/gdb/stack.c:1116
    #14 0x000055555f526c6d in backtrace_command_1 (fp_opts=..., bt_opts=..., count_exp=0x0, from_tty=0) at /home/simark/src/binutils-gdb/gdb/stack.c:2079
    #15 0x000055555f527ae5 in backtrace_command (arg=0x0, from_tty=0) at /home/simark/src/binutils-gdb/gdb/stack.c:2198

The problem is that the type that gets passed down to
dwarf_expr_context::fetch_result is a typedef whose size has never been
computed yet (check_typedef has never been called on it).  As we get in
the DWARF_VALUE_STACK case (line 1028 of dwarf2/expr.c), the `len`
variable is therefore set to 0, instead of the actual type length.  We
then call allocate_value on subobj_type, which does call check_typedef,
so the length of the typedef gets filled in at that point.  We end up
passing to the copy function  a source array view of length 0 and a
target array view of length 4, and the assertion fails.

Fix this by calling check_typedef on both type and subobj_type at the
beginning of fetch_result.

I tried writing a test for this using the DWARF assembler, but I haven't
succeeded.  It's possible that we need to get into this specific code
path (value_of_dwarf_reg_entry and all) to manage to get to
dwarf_expr_context::fetch_result with a typedef type that has never been
resolved.  In all my attempts, the typedef would always be resolved
already, so the bug wouldn't show up.  We don't have any tests using
entry values, I think it would need DWARF machinery that we haven't
implemented yet, like unwind information (can't have entry values with a
single stack frame).

As a fallback, I could always add a gdb.dwarf2 test with a
compiler-generated .S file, we have a few of those.  I'm not sure if
that's acceptable today though, since the DWARF assembler should really
be preferred, it makes tests more maintainable and extensible.

Change-Id: I182733ad08e34df40d8bcc47af72c482fabf4900
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29374
---
 gdb/dwarf2/expr.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 998625833366..6dc5132fb801 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -929,6 +929,11 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
   if (subobj_type == nullptr)
     subobj_type = type;
 
+  /* Ensure that, if TYPE or SUBOBJ_TYPE are typedefs, their length is filled
+     in instead of being zero.  */
+  check_typedef (type);
+  check_typedef (subobj_type);
+
   if (this->m_pieces.size () > 0)
     {
       ULONGEST bit_size = 0;

base-commit: 561e83f7c5cdfb2737ba36a04ea008caa6bcaa36
-- 
2.37.1



More information about the Gdb-patches mailing list