]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
gdb: resolve type to target_type in expression evaluation
authorStephan Rohr <stephan.rohr@intel.com>
Wed, 20 Aug 2025 13:06:23 +0000 (06:06 -0700)
committerStephan Rohr <stephan.rohr@intel.com>
Wed, 24 Sep 2025 08:31:52 +0000 (01:31 -0700)
commit3a3c3a0e7280ef8907d62ea83706a2ef3081831b
tree70c20a5448526e6d61dbd4c30a4349a0782b2c41
parent4c47471ba4cfd59206ce1cb33ae2f19ced2f29cd
gdb: resolve type to target_type in expression evaluation

If an expression is evaluated with 'EVAL_AVOID_SIDE_EFFECTS', we're
essentially interested in compatibility of the operands.  If there is an
operand of reference type, this would give us a memory value that would
cause a failure if GDB attempts to access the contents.

GDB fails to evaluate binary expressions for the following example:

  struct
  {
    int &get () { return x; };

    int x = 1;
  } v_struct;

The GDB output is:

  (gdb) print v_struct3.get () == 1 && v_struct3.get () == 2
  Cannot access memory at address 0x0
  (gdb) print v_struct3.get () == 1 || v_struct3.get () == 2
  Cannot access memory at address 0x0

Likewise, GDB fails to resolve the type for some expressions:

  (gdb) ptype v_struct.get ()
  type = int &
  (gdb) ptype v_struct.get () == 1
  Cannot access memory at address 0x0
  (gdb) ptype v_struct.get () + 1
  Cannot access memory at address 0x0
  (gdb) ptype v_struct.get () && 1
  Cannot access memory at address 0x0
  (gdb) ptype v_struct.get () || 1
  Cannot access memory at address 0x0
  (gdb) ptype !v_struct.get ()
  Cannot access memory at address 0x0
  (gdb) ptype v_struct.get () ? 2 : 3
  Cannot access memory at address 0x0
  (gdb) ptype v_struct.get () | 1
  Cannot access memory at address 0x0

Expression evaluation uses helper functions such as 'value_equal',
'value_logical_not', etc.  These helper functions do not take a 'noside'
argument and if one of their value arguments was created from a function
call that returns a reference type when noside == EVAL_AVOID_SIDE_EFFECTS,
GDB attempts to read from an invalid memory location.  Consider the
following call stack of the 'ptype v_struct.get () + 1' command at the time
of assertion when the memory error is raised:

  #0  memory_error (err=TARGET_XFER_E_IO, memaddr=0) at gdb/corefile.c:114
  #1  read_value_memory (val=.., bit_offset=0, stack=false, memaddr=0,
      buffer=.. "", length=4) at gdb/valops.c:1075
  #2  value::fetch_lazy_memory (this=..) at gdb/value.c:3996
  #3  value::fetch_lazy (this=..) at gdb/value.c:4135
  #4  value::contents_writeable (this=..) at gdb/value.c:1329
  #5  value::contents (this=..) at gdb/value.c:1319
  #6  value_as_mpz (val=..) at gdb/value.c:2685
  #7  scalar_binop (arg1=.., arg2=.., op=BINOP_ADD) at gdb/valarith.c:1240
  #8  value_binop (arg1=.., arg2=.., op=BINOP_ADD) at gdb/valarith.c:1489
  #9  eval_op_add (expect_type=0x0, exp=.., noside=EVAL_AVOID_SIDE_EFFECTS,
      arg1=.., arg2=..) at gdb/eval.c:1333
  #10 expr::add_operation::evaluate (this=.., expect_type=0x0, exp=..,
      noside=EVAL_AVOID_SIDE_EFFECTS) at gdb/expop.h:1209
  #11 expression::evaluate (this=.., expect_type=0x0,
      noside=EVAL_AVOID_SIDE_EFFECTS) at gdb/eval.c:110
  #12 expression::evaluate_type (this=..) at gdb/expression.h:242

'add_operation::evaluate' calls the helper 'eval_op_add' which attempts
to read from the unresolved memory location.  Convert to the target type
to avoid such problems.  The patch is implemented in 'expop.h' for the
following reasons:

  * Support templated classes without explicit helpers, e.g.,
    'binop_operation' and 'comparison_operation'.
  * Stripping references in 'binop_promote' requires additional
    refactoring beyond this patch as we would need to carry on the
    'noside' parameter.

The above failures are resolved with the patch:

  (gdb) print v_struct.get () == 1 && v_struct3.get () == 2
  $1 = false
  (gdb) print v_struct.get () == 1 || v_struct3.get () == 2
  $2 = true
  (gdb) ptype v_struct.get ()
  type = int &
  (gdb) ptype v_struct.get () == 1
  type = bool
  (gdb) ptype v_struct.get () + 1
  type = int
  (gdb) ptype v_struct.get () && 1
  type = bool
  (gdb) ptype v_struct.get () || 1
  type = bool
  (gdb) ptype !v_struct.get ()
  type = bool
  (gdb) ptype v_struct.get () ? 2 : 3
  type = int
  (gdb) ptype v_struct.get () | 1
  type = int

Co-Authored-By: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Approved-By: Tom Tromey <tom@tromey.com>
gdb/eval.c
gdb/expop.h
gdb/testsuite/gdb.cp/eval-reference-type.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/eval-reference-type.exp [new file with mode: 0644]