)]}'
{
  "commit": "c3e06e640e53afa75d82b44f4b701815be3db19b",
  "tree": "89685d5fc42fba6da0aa415ce025ce787ee47b62",
  "parents": [
    "d1648ffe809ad288d989cd4f6794c01f524471f2"
  ],
  "author": {
    "name": "Tom de Vries",
    "email": "tdevries@suse.de",
    "time": "Mon Feb 19 09:59:15 2024 +0100"
  },
  "committer": {
    "name": "Tom de Vries",
    "email": "tdevries@suse.de",
    "time": "Mon Feb 19 09:59:15 2024 +0100"
  },
  "message": "[gdb/exp] Fix printing of out of bounds struct members\n\nWhen building gdb with -O0 -fsanitize\u003daddress, and running test-case\ngdb.ada/uninitialized_vars.exp, I run into:\n...\n(gdb) info locals\na \u003d 0\nz \u003d (a \u003d\u003e 1, b \u003d\u003e false, c \u003d\u003e 2.0)\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\u003d\u003d66372\u003d\u003dERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000097f58 at pc 0xffff52c0da1c bp 0xffffc90a1d40 sp 0xffffc90a1d80\nREAD of size 4 at 0x602000097f58 thread T0\n    #0 0xffff52c0da18 in memmove (/lib64/libasan.so.8+0x6da18)\n    #1 0xbcab24 in unsigned char* std::__copy_move_backward\u003cfalse, true, std::random_access_iterator_tag\u003e::__copy_move_b\u003cunsigned char const, unsigned char\u003e(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/13/bits/stl_algobase.h:748\n    #2 0xbc9bf4 in unsigned char* std::__copy_move_backward_a2\u003cfalse, unsigned char const*, unsigned char*\u003e(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/13/bits/stl_algobase.h:769\n    #3 0xbc898c in unsigned char* std::__copy_move_backward_a1\u003cfalse, unsigned char const*, unsigned char*\u003e(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/13/bits/stl_algobase.h:778\n    #4 0xbc715c in unsigned char* std::__copy_move_backward_a\u003cfalse, unsigned char const*, unsigned char*\u003e(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/13/bits/stl_algobase.h:807\n    #5 0xbc4e6c in unsigned char* std::copy_backward\u003cunsigned char const*, unsigned char*\u003e(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/13/bits/stl_algobase.h:867\n    #6 0xbc2934 in void gdb::copy\u003cunsigned char const, unsigned char\u003e(gdb::array_view\u003cunsigned char const\u003e, gdb::array_view\u003cunsigned char\u003e) gdb/../gdbsupport/array-view.h:223\n    #7 0x20e0100 in value::contents_copy_raw(value*, long, long, long) gdb/value.c:1239\n    #8 0x20e9830 in value::primitive_field(long, int, type*) gdb/value.c:3078\n    #9 0x20e98f8 in value_field(value*, int) gdb/value.c:3095\n    #10 0xcafd64 in print_field_values gdb/ada-valprint.c:658\n    #11 0xcb0fa0 in ada_val_print_struct_union gdb/ada-valprint.c:857\n    #12 0xcb1bb4 in ada_value_print_inner(value*, ui_file*, int, value_print_options const*) gdb/ada-valprint.c:1042\n    #13 0xc66e04 in ada_language::value_print_inner(value*, ui_file*, int, value_print_options const*) const (/home/vries/gdb/build/gdb/gdb+0xc66e04)\n    #14 0x20ca1e8 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) gdb/valprint.c:1092\n    #15 0x20caabc in common_val_print_checked(value*, ui_file*, int, value_print_options const*, language_defn const*) gdb/valprint.c:1184\n    #16 0x196c524 in print_variable_and_value(char const*, symbol*, frame_info_ptr, ui_file*, int) gdb/printcmd.c:2355\n    #17 0x1d99ca0 in print_variable_and_value_data::operator()(char const*, symbol*) gdb/stack.c:2308\n    #18 0x1dabca0 in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::bind\u003cprint_variable_and_value_data\u003e(print_variable_and_value_data\u0026)::{lambda(gdb::fv_detail::erased_callable, char const*, symbol*)#1}::operator()(gdb::fv_detail::erased_callable, char const*, symbol*) const gdb/../gdbsupport/function-view.h:305\n    #19 0x1dabd14 in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::bind\u003cprint_variable_and_value_data\u003e(print_variable_and_value_data\u0026)::{lambda(gdb::fv_detail::erased_callable, char const*, symbol*)#1}::_FUN(gdb::fv_detail::erased_callable, char const*, symbol*) gdb/../gdbsupport/function-view.h:299\n    #20 0x1dab34c in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::operator()(char const*, symbol*) const gdb/../gdbsupport/function-view.h:289\n    #21 0x1d9963c in iterate_over_block_locals gdb/stack.c:2240\n    #22 0x1d99790 in iterate_over_block_local_vars(block const*, gdb::function_view\u003cvoid (char const*, symbol*)\u003e) gdb/stack.c:2259\n    #23 0x1d9a598 in print_frame_local_vars gdb/stack.c:2380\n    #24 0x1d9afac in info_locals_command(char const*, int) gdb/stack.c:2458\n    #25 0xfd7b30 in do_simple_func gdb/cli/cli-decode.c:95\n    #26 0xfe5a2c in cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735\n    #27 0x1f03790 in execute_command(char const*, int) gdb/top.c:575\n    #28 0x1384080 in command_handler(char const*) gdb/event-top.c:566\n    #29 0x1384e2c in command_line_handler(std::unique_ptr\u003cchar, gdb::xfree_deleter\u003cchar\u003e \u003e\u0026\u0026) gdb/event-top.c:802\n    #30 0x1f731e4 in tui_command_line_handler gdb/tui/tui-interp.c:104\n    #31 0x1382a58 in gdb_rl_callback_handler gdb/event-top.c:259\n    #32 0x21dbb80 in rl_callback_read_char readline/readline/callback.c:290\n    #33 0x1382510 in gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195\n    #34 0x138277c in gdb_rl_callback_read_char_wrapper gdb/event-top.c:234\n    #35 0x1fe9b40 in stdin_event_handler gdb/ui.c:155\n    #36 0x35ff1bc in handle_file_event gdbsupport/event-loop.cc:573\n    #37 0x35ff9d8 in gdb_wait_for_event gdbsupport/event-loop.cc:694\n    #38 0x35fd284 in gdb_do_one_event(int) gdbsupport/event-loop.cc:264\n    #39 0x1768080 in start_event_loop gdb/main.c:408\n    #40 0x17684c4 in captured_command_loop gdb/main.c:472\n    #41 0x176cfc8 in captured_main gdb/main.c:1342\n    #42 0x176d088 in gdb_main(captured_main_args*) gdb/main.c:1361\n    #43 0xb73edc in main gdb/gdb.c:39\n    #44 0xffff519b09d8 in __libc_start_call_main (/lib64/libc.so.6+0x309d8)\n    #45 0xffff519b0aac in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x30aac)\n    #46 0xb73c2c in _start (/home/vries/gdb/build/gdb/gdb+0xb73c2c)\n\n0x602000097f58 is located 0 bytes after 8-byte region [0x602000097f50,0x602000097f58)\nallocated by thread T0 here:\n    #0 0xffff52c65218 in calloc (/lib64/libasan.so.8+0xc5218)\n    #1 0xcbc278 in xcalloc gdb/alloc.c:97\n    #2 0x35f21e8 in xzalloc(unsigned long) gdbsupport/common-utils.cc:29\n    #3 0x20de270 in value::allocate_contents(bool) gdb/value.c:937\n    #4 0x20edc08 in value::fetch_lazy() gdb/value.c:4033\n    #5 0x20dadc0 in value::entirely_covered_by_range_vector(std::vector\u003crange, std::allocator\u003crange\u003e \u003e const\u0026) gdb/value.c:229\n    #6 0xcb2298 in value::entirely_optimized_out() gdb/value.h:560\n    #7 0x20ca6fc in value_check_printable gdb/valprint.c:1133\n    #8 0x20caa8c in common_val_print_checked(value*, ui_file*, int, value_print_options const*, language_defn const*) gdb/valprint.c:1182\n    #9 0x196c524 in print_variable_and_value(char const*, symbol*, frame_info_ptr, ui_file*, int) gdb/printcmd.c:2355\n    #10 0x1d99ca0 in print_variable_and_value_data::operator()(char const*, symbol*) gdb/stack.c:2308\n    #11 0x1dabca0 in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::bind\u003cprint_variable_and_value_data\u003e(print_variable_and_value_data\u0026)::{lambda(gdb::fv_detail::erased_callable, char const*, symbol*)#1}::operator()(gdb::fv_detail::erased_callable, char const*, symbol*) const gdb/../gdbsupport/function-view.h:305\n    #12 0x1dabd14 in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::bind\u003cprint_variable_and_value_data\u003e(print_variable_and_value_data\u0026)::{lambda(gdb::fv_detail::erased_callable, char const*, symbol*)#1}::_FUN(gdb::fv_detail::erased_callable, char const*, symbol*) gdb/../gdbsupport/function-view.h:299\n    #13 0x1dab34c in gdb::function_view\u003cvoid (char const*, symbol*)\u003e::operator()(char const*, symbol*) const gdb/../gdbsupport/function-view.h:289\n    #14 0x1d9963c in iterate_over_block_locals gdb/stack.c:2240\n    #15 0x1d99790 in iterate_over_block_local_vars(block const*, gdb::function_view\u003cvoid (char const*, symbol*)\u003e) gdb/stack.c:2259\n    #16 0x1d9a598 in print_frame_local_vars gdb/stack.c:2380\n    #17 0x1d9afac in info_locals_command(char const*, int) gdb/stack.c:2458\n    #18 0xfd7b30 in do_simple_func gdb/cli/cli-decode.c:95\n    #19 0xfe5a2c in cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735\n    #20 0x1f03790 in execute_command(char const*, int) gdb/top.c:575\n    #21 0x1384080 in command_handler(char const*) gdb/event-top.c:566\n    #22 0x1384e2c in command_line_handler(std::unique_ptr\u003cchar, gdb::xfree_deleter\u003cchar\u003e \u003e\u0026\u0026) gdb/event-top.c:802\n    #23 0x1f731e4 in tui_command_line_handler gdb/tui/tui-interp.c:104\n    #24 0x1382a58 in gdb_rl_callback_handler gdb/event-top.c:259\n    #25 0x21dbb80 in rl_callback_read_char readline/readline/callback.c:290\n    #26 0x1382510 in gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195\n    #27 0x138277c in gdb_rl_callback_read_char_wrapper gdb/event-top.c:234\n    #28 0x1fe9b40 in stdin_event_handler gdb/ui.c:155\n    #29 0x35ff1bc in handle_file_event gdbsupport/event-loop.cc:573\n\nSUMMARY: AddressSanitizer: heap-buffer-overflow (/lib64/libasan.so.8+0x6da18) in memmove\n...\n\nThe error happens when trying to print either variable y or y2:\n...\n   type Variable_Record (A : Boolean :\u003d True) is record\n      case A is\n         when True \u003d\u003e\n            B : Integer;\n         when False \u003d\u003e\n            C : Float;\n            D : Integer;\n      end case;\n   end record;\n   Y  : Variable_Record :\u003d (A \u003d\u003e True, B \u003d\u003e 1);\n   Y2 : Variable_Record :\u003d (A \u003d\u003e False, C \u003d\u003e 1.0, D \u003d\u003e 2);\n...\nwhen the variables are uninitialized.\n\nThe error happens only when printing the entire variable:\n...\n(gdb) p y.a\n$2 \u003d 216\n(gdb) p y.b\nThere is no member named b.\n(gdb) p y.c\n$3 \u003d 9.18340949e-41\n(gdb) p y.d\n$4 \u003d 1\n(gdb) p y\n\u003cAddressSanitizer: heap-buffer-overflow\u003e\n...\n\nThe error happens as follows:\n- field a functions as discriminant, choosing either the b, or c+d variant.\n- when y.a happens to be set to 216, as above, gdb interprets this as the\n  variable having the c+d variant (which is why trying to print y.b fails).\n- when printing y, gdb allocates a value, copies the bytes into it from the\n  target, and then prints the value.\n- gdb allocates the value using the type size, which is 8.  It\u0027s 8 because\n  that\u0027s what the DW_AT_byte_size indicates.  Note that for valid values of a,\n  it gives correct results: if a is 0 (c+d variant), size is 12, if a is 1\n  (b variant), size is 8.\n- gdb tries to print field d, which is at an 8 byte offset, and that results\n  in a out-of-bounds access for the allocated 8-byte value.\n\nFix this by handling this case in value::contents_copy_raw, such that we have:\n...\n(gdb) p y\n$1 \u003d (a \u003d\u003e 24, c \u003d\u003e 9.18340949e-41,\n      d \u003d\u003e \u003cerror reading variable: access outside bounds of object\u003e)\n...\n\nAn alternative (additional) fix could be this: in compute_variant_fields_inner\ngdb reads the discriminant y.a to decide which variant is active.  It would be\nnice to detect that the value (y.a \u003d\u003d 24) is not a valid Boolean, and give up\non choosing a variant altoghether.  However, the situation regarding the\ninternal type CODE_TYPE_BOOL is currently ambiguous (see PR31282) and it\u0027s not\npossible to reliably decide what valid values are.\n\nThe test-case source file gdb.ada/uninitialized-variable-record/parse.adb is\na reduced version of gdb.ada/uninitialized_vars/parse.adb, so it copies the\ncopyright years.\n\nNote that the test-case needs gcc-12 or newer, it\u0027s unsupported for older gcc\nversions. [ So, it would be nice to rewrite it into a dwarf assembly\ntest-case. ]\n\nThe test-case loops over all languages.  This is inherited from an earlier\nattempt to fix this, which had language-specific fixes (in print_field_values,\ncp_print_value_fields, pascal_object_print_value_fields and\nf_language::value_print_inner).  I\u0027ve left this in, but I suppose it\u0027s not\nstrictly necessary anymore.\n\nTested on x86_64-linux.\n\nPR exp/31258\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d31258\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "7fc72395edf7ed5c3988eaa49fb44a222877883b",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.ada/uninitialized-variable-record.exp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "f00c75ca2dcb593eadcdb6fcc8f7597f4d2ef528",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.ada/uninitialized-variable-record/parse.adb"
    },
    {
      "type": "modify",
      "old_id": "8840aa41a332cd8cc0f34602d047238617bdc279",
      "old_mode": 33188,
      "old_path": "gdb/value.c",
      "new_id": "bea34e556a60e3722626cf150064a42d50b075af",
      "new_mode": 33188,
      "new_path": "gdb/value.c"
    }
  ]
}
