Compile one C++ source file, as follows: struct category { virtual const char* name() const = 0; }; struct cat : category { const char* name() const { return "miaow"; } }; category* getcat() { static cat c; return &c; } struct error_code { error_code(int i = 0) : m_value(i), m_cat(getcat()) { } void assign(int i) { m_value = i; } int value() const { return m_value; } int m_value; category* m_cat; }; int f(error_code& ec) { ec.assign(1); return ec.value(); } int g(error_code& ec) { return f(ec); } int main() { error_code ec; return g(ec); } Add one Python file: class ErrorCodePrinter: "print an error_code" def __init__ (self, val): self.val = val @staticmethod def _category_name(cat): "Call the virtual function that overrides category::name()" gdb.set_convenience_variable('__cat', cat) return gdb.parse_and_eval('$__cat->name()').string() def to_string (self): value = self.val['m_value'] category = self._category_name(self.val['m_cat']) return 'error_code = {"%s": %d}' % (category, value) def ec_lookup_function(val): typ = val.type if typ.code == gdb.TYPE_CODE_REF: typ = typ.target() if str(typ) == 'error_code': return ErrorCodePrinter(val) return None gdb.pretty_printers.append(ec_lookup_function) Prepare an executable: g++ -g ec.cc -o ec And bake in the oven until it catches fire: gdb -q -iex "add-auto-load-safe-path $PWD/ec-gdb.py" -ex start -ex n -ex 'p &ec' -ex step -ex step -ex n -ex up -ex up ec Reading symbols from ec... Temporary breakpoint 1 at 0x40115e: file ec.C, line 37. Starting program: /tmp/ec Temporary breakpoint 1, main () at ec.C:37 37 error_code ec; 38 return g(ec); $1 = (error_code *) 0x7fffffffd790 g (ec=error_code = {"miaow": 0}) at ec.C:32 32 return f(ec); f (ec=error_code = {"miaow": 0}) at ec.C:26 26 ec.assign(1); 27 return ec.value(); #1 0x0000000000401154 in g (ec= Fatal signal: Segmentation fault ----- Backtrace ----- 0x4bcd33 gdb_internal_backtrace_1 /home/jwakely/src/binutils-gdb/gdb/bt-utils.c:121 0x4bcd33 _Z22gdb_internal_backtracev /home/jwakely/src/binutils-gdb/gdb/bt-utils.c:164 0x5b32b1 handle_fatal_signal /home/jwakely/src/binutils-gdb/gdb/event-top.c:896 0x5b33f4 handle_sigsegv /home/jwakely/src/binutils-gdb/gdb/event-top.c:969 0x7f8d6d648a1f ??? ../sysdeps/unix/sysv/linux/sigaction.c:665 0x4b7ba5 _ZN22scoped_debug_start_endC2ERbPKcS2_S2_S2_S2_z /home/jwakely/src/binutils-gdb/gdb/../gdbsupport/common-debug.h:108 0x5cb846 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:181 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 [... several thousand more frames ...] 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5cb879 _Z26frame_unwind_find_by_frameP10frame_infoPPv /home/jwakely/src/binutils-gdb/gdb/frame-unwind.c:184 0x5ce738 _Z17frame_unwind_archP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2896 0x5ce784 frame_unwind_pc /home/jwakely/src/binutils-gdb/gdb/frame.c:944 0x5ce8cb _Z12get_frame_pcP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2571 0x5ce8cb _Z26get_frame_address_in_blockP10frame_info /home/jwakely/src/binutils-gdb/gdb/frame.c:2601 0x55727c dwarf2_frame_cache /home/jwakely/src/binutils-gdb/gdb/dwarf2/frame.c:903 0x558303 dwarf2_frame_prev_register /home/jwakely/src/binutils-gdb/gdb/dwarf2/frame.c:1136 0x5cee9b _Z27frame_unwind_register_valueP10frame_infoi /home/jwakely/src/binutils-gdb/gdb/frame.c:1233 0x5cf23a _Z21frame_register_unwindP10frame_infoiPiS1_P9lval_typePmS1_Ph /home/jwakely/src/binutils-gdb/gdb/frame.c:1143 0x5cf5c8 _Z21frame_unwind_registerP10frame_infoiPh /home/jwakely/src/binutils-gdb/gdb/frame.c:1199 0x5fe4e0 i386_unwind_pc /home/jwakely/src/binutils-gdb/gdb/i386-tdep.c:1970 0x5ce78f frame_unwind_pc /home/jwakely/src/binutils-gdb/gdb/frame.c:948 0x5ce869 _Z25get_frame_pc_if_availableP10frame_infoPm /home/jwakely/src/binutils-gdb/gdb/frame.c:2582 0x761b40 _Z16print_frame_infoRK19frame_print_optionsP10frame_infoi10print_whatii /home/jwakely/src/binutils-gdb/gdb/stack.c:1185 0x76246b _Z17print_stack_frameP10frame_infoi10print_whati /home/jwakely/src/binutils-gdb/gdb/stack.c:366 0x762502 _Z26print_stack_frame_to_uioutP6ui_outP10frame_infoi10print_whati /home/jwakely/src/binutils-gdb/gdb/stack.c:345 0x4eff7a cli_on_user_selected_context_changed /home/jwakely/src/binutils-gdb/gdb/cli/cli-interp.c:277 0x764463 _ZNKSt8functionIFv10enum_flagsI23user_selected_what_flagEEEclES2_ /usr/include/c++/11/bits/std_function.h:560 0x764463 _ZNK3gdb9observers10observableIJ10enum_flagsI23user_selected_what_flagEEE6notifyES4_ /home/jwakely/src/binutils-gdb/gdb/../gdbsupport/observable.h:150 0x764463 up_command /home/jwakely/src/binutils-gdb/gdb/stack.c:2690 0x4ee2a4 _Z8cmd_funcP16cmd_list_elementPKci /home/jwakely/src/binutils-gdb/gdb/cli/cli-decode.c:2459 0x7bdbe1 _Z15execute_commandPKci /home/jwakely/src/binutils-gdb/gdb/top.c:670 0x66dcd2 catch_command_errors /home/jwakely/src/binutils-gdb/gdb/main.c:523 0x66dd9f execute_cmdargs /home/jwakely/src/binutils-gdb/gdb/main.c:618 0x66f4b4 captured_main_1 /home/jwakely/src/binutils-gdb/gdb/main.c:1317 0x66ff5a captured_main /home/jwakely/src/binutils-gdb/gdb/main.c:1338 0x66ff5a _Z8gdb_mainP18captured_main_args /home/jwakely/src/binutils-gdb/gdb/main.c:1363 0x431624 main /home/jwakely/src/binutils-gdb/gdb/gdb.c:32 --------------------- A fatal error internal to GDB has been detected, further debugging is not possible. GDB will now terminate. This is a bug, please report it. For instructions, see: <https://www.gnu.org/software/gdb/bugs/>. Segmentation fault (core dumped)
On Windows I get a use-after-free of a frame_info pointer. It happens because the target function call gdb.parse_and_eval('$__cat->name()') leads to reinit_frame_cache(), and print_frame_info() continues on with that now stale 'frame' pointer. Full stack traces: > unhandled exception code: 0xC0000005 (ACCESS_VIOLATION) > exception on: '1 [4648]' > 0x000000013F350000 C:\gdb\build64\gdb-git-python\gdb\gdb.exe > 0x000000013F4A5687 C:\src\repos\binutils-gdb.git\gdb\frame.c:2545:3 [get_frame_pc_if_available(frame_info*, unsigned long long*)] > 0x000000013F5F7E57 C:\src\repos\binutils-gdb.git\gdb\stack.c:1201:37 [print_frame_info(frame_print_options const&, frame_info*, int, print_what, int, int)] > 0x000000013F5F887F C:\src\repos\binutils-gdb.git\gdb\stack.c:366:24 [print_stack_frame(frame_info*, int, print_what, int)] > 0x000000013F4F5A97 C:\src\repos\binutils-gdb.git\gdb\infrun.c:8420:23 [print_stop_location] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:8436:25 [print_stop_event(ui_out*, bool)] > 0x000000013F6630BD C:\src\repos\binutils-gdb.git\gdb\tui\tui-interp.c:99:19 [tui_on_normal_stop] > 0x000000013F4F6F4F c:\msys64\mingw64\x86_64-w64-mingw32\include\c++\11.2.0\bits\std_function.h:560:9 [std::function<void (bpstats*, int)>::operator()(bpstats*, int) const] > c:\src\repos\binutils-gdb.git\gdbsupport\observable.h:150:9 [gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:8705:40 [normal_stop()] > 0x000000013F502B42 C:\src\repos\binutils-gdb.git\gdb\infrun.c:4157:29 [fetch_inferior_event()] > 0x000000013F3885FA C:\src\repos\binutils-gdb.git\gdb\async-event.c:335:31 [check_async_event_handlers()] > 0x000000013F795901 C:\src\repos\binutils-gdb.git\gdbsupport\event-loop.cc:216:37 [gdb_do_one_event()] > 0x000000013F64CD5B C:\src\repos\binutils-gdb.git\gdb\top.c:529:27 [wait_sync_command_done()] > 0x000000013F64D650 C:\src\repos\binutils-gdb.git\gdb\top.c:546:28 [maybe_wait_sync_command_done(int)] > C:\src\repos\binutils-gdb.git\gdb\top.c:687:36 [execute_command(char const*, int)] > 0x000000013F5213BB C:\src\repos\binutils-gdb.git\gdb\main.c:523:15 [catch_command_errors] > 0x000000013F5214E5 C:\src\repos\binutils-gdb.git\gdb\main.c:618:30 [execute_cmdargs] > 0x000000013F524693 C:\src\repos\binutils-gdb.git\gdb\main.c:1322:19 [captured_main_1] > 0x000000013F5250FC C:\src\repos\binutils-gdb.git\gdb\main.c:1343:19 [captured_main] > C:\src\repos\binutils-gdb.git\gdb\main.c:1368:21 [gdb_main(captured_main_args*)] > 0x000000013FA3C146 C:\src\repos\binutils-gdb.git\gdb\gdb.c:32:19 [main] > 0x000000013F351430 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:345:15 [__tmainCRTStartup] > 0x000000013F3515B5 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:220:9 [mainCRTStartup] > read access violation at 0x000000039C0B0190 > freed block 0x000000039C0B0020 (size 4064, offset +368) > allocated on: (#180516) '1 [4648]' > [malloc] > 0x000000013F350000 C:\gdb\build64\gdb-git-python\gdb\gdb.exe > 0x000000013F37AEFB C:\src\repos\binutils-gdb.git\gdb\alloc.c:60:16 [xmalloc] > 0x000000013F7B8E34 C:\src\repos\binutils-gdb.git\libiberty\obstack.c:94:12 [call_chunkfun] > C:\src\repos\binutils-gdb.git\libiberty\obstack.c:141:37 [_obstack_begin_worker] > 0x000000013F4A504B C:\src\repos\binutils-gdb.git\gdb\frame.c:2000:3 [reinit_frame_cache()] > 0x000000013F4FF614 C:\src\repos\binutils-gdb.git\gdb\infrun.c:6021:18 [handle_signal_stop] > 0x000000013F5012A0 C:\src\repos\binutils-gdb.git\gdb\infrun.c:4500:26 [handle_stop_requested] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:4494:1 [handle_stop_requested] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:5765:33 [handle_inferior_event] > 0x000000013F502A44 C:\src\repos\binutils-gdb.git\gdb\infrun.c:4121:27 [fetch_inferior_event()] > 0x000000013F3885FA C:\src\repos\binutils-gdb.git\gdb\async-event.c:335:31 [check_async_event_handlers()] > 0x000000013F795901 C:\src\repos\binutils-gdb.git\gdbsupport\event-loop.cc:216:37 [gdb_do_one_event()] > 0x000000013F64CD5B C:\src\repos\binutils-gdb.git\gdb\top.c:529:27 [wait_sync_command_done()] > 0x000000013F64D650 C:\src\repos\binutils-gdb.git\gdb\top.c:546:28 [maybe_wait_sync_command_done(int)] > C:\src\repos\binutils-gdb.git\gdb\top.c:687:36 [execute_command(char const*, int)] > 0x000000013F5213BB C:\src\repos\binutils-gdb.git\gdb\main.c:523:15 [catch_command_errors] > 0x000000013F5214E5 C:\src\repos\binutils-gdb.git\gdb\main.c:618:30 [execute_cmdargs] > 0x000000013F524693 C:\src\repos\binutils-gdb.git\gdb\main.c:1322:19 [captured_main_1] > 0x000000013F5250FC C:\src\repos\binutils-gdb.git\gdb\main.c:1343:19 [captured_main] > C:\src\repos\binutils-gdb.git\gdb\main.c:1368:21 [gdb_main(captured_main_args*)] > 0x000000013FA3C146 C:\src\repos\binutils-gdb.git\gdb\gdb.c:32:19 [main] > 0x000000013F351430 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:345:15 [__tmainCRTStartup] > 0x000000013F3515B5 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:220:9 [mainCRTStartup] > freed on: '1 [4648]' > [free] > 0x000000013F350000 C:\gdb\build64\gdb-git-python\gdb\gdb.exe > 0x000000013F7B9051 C:\src\repos\binutils-gdb.git\libiberty\obstack.c:103:5 [call_freefun] > C:\src\repos\binutils-gdb.git\libiberty\obstack.c:280:7 [_obstack_free] > 0x000000013F4A502B C:\src\repos\binutils-gdb.git\gdb\frame.c:1999:3 [reinit_frame_cache()] > 0x000000013F4FAE4A C:\src\repos\binutils-gdb.git\gdb\infrun.c:3130:25 [proceed(unsigned long long, gdb_signal)] > 0x000000013F4E4C9B C:\src\repos\binutils-gdb.git\gdb\infcall.c:611:15 [run_inferior_call] > C:\src\repos\binutils-gdb.git\gdb\infcall.c:1277:27 [call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*)] > 0x000000013F4E606A C:\src\repos\binutils-gdb.git\gdb\infcall.c:742:38 [call_function_by_hand(value*, type*, gdb::array_view<value*>)] > 0x000000013F489AE9 C:\src\repos\binutils-gdb.git\gdb\eval.c:674:36 [evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*)] > 0x000000013F48CEFA C:\src\repos\binutils-gdb.git\gdb\eval.c:966:34 [expr::structop_base_operation::evaluate_funcall(type*, expression*, noside, std::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&)] > 0x000000013F920A29 C:\src\repos\binutils-gdb.git\gdb\expop.h:2178:54 [expr::funcall_operation::evaluate(type*, expression*, noside)] > 0x000000013F48891B C:\src\repos\binutils-gdb.git\gdb\eval.c:101:39 [expression::evaluate(type*, noside)] > 0x000000013F488BB9 C:\src\repos\binutils-gdb.git\gdb\eval.c:115:24 [evaluate_expression(expression*, type*)] > C:\src\repos\binutils-gdb.git\gdb\eval.c:74:30 [parse_and_eval(char const*)] > 0x000000013F59B899 C:\src\repos\binutils-gdb.git\gdb\python\python.c:945:31 [gdbpy_parse_and_eval] > 0x0000000069E90000 c:\gdb\gdb-libs64\Python27\python27.dll > 0x0000000069F88EA8 [PyCFunction_Call] > 0x0000000069FEDFA7 [PyEval_GetFuncDesc] > 0x0000000069FEB49A [PyEval_EvalFrameEx] > 0x0000000069FEE177 [PyEval_GetFuncDesc] > 0x0000000069FEE02E [PyEval_GetFuncDesc] > 0x0000000069FEB49A [PyEval_EvalFrameEx] > 0x0000000069FECA10 [PyEval_EvalCodeEx] > 0x0000000069F77037 [PyFunction_SetClosure] > 0x0000000069F42D22 [PyObject_Call] > 0x0000000069F575D8 [PyMethod_New] > 0x0000000069F42D22 [PyObject_Call] > 0x0000000069F4359B [PyObject_CallMethodObjArgs] > 0x000000013F350000 C:\gdb\build64\gdb-git-python\gdb\gdb.exe > 0x000000013F589B6E C:\src\repos\binutils-gdb.git\gdb\python\py-prettyprint.c:200:17 [pretty_print_one_value] > 0x000000013F589CB5 C:\src\repos\binutils-gdb.git\gdb\python\py-prettyprint.c:286:69 [print_string_repr] > C:\src\repos\binutils-gdb.git\gdb\python\py-prettyprint.c:636:36 [gdbpy_apply_pretty_printer] > 0x000000013F58A934 C:\src\repos\binutils-gdb.git\gdb\python\py-prettyprint.c:620:36 [gdbpy_apply_val_pretty_printer(extension_language_defn const*, value*, ui_file*, int, value_print_options const*, language_defn const*)] > 0x000000013F493319 C:\src\repos\binutils-gdb.git\gdb\extension.c:488:51 [apply_ext_lang_val_pretty_printer(value*, ui_file*, int, value_print_options const*, language_defn const*)] > 0x000000013F68B755 C:\src\repos\binutils-gdb.git\gdb\valprint.c:1028:47 [do_val_print] > 0x000000013F5F5A06 C:\src\repos\binutils-gdb.git\gdb\stack.c:489:33 [print_frame_arg] > 0x000000013F5F680C C:\src\repos\binutils-gdb.git\gdb\stack.c:893:22 [print_frame_args] > 0x000000013F5F82E0 C:\src\repos\binutils-gdb.git\gdb\stack.c:1407:25 [print_frame] > C:\src\repos\binutils-gdb.git\gdb\stack.c:1124:17 [print_frame_info(frame_print_options const&, frame_info*, int, print_what, int, int)] > 0x000000013F5F887F C:\src\repos\binutils-gdb.git\gdb\stack.c:366:24 [print_stack_frame(frame_info*, int, print_what, int)] > 0x000000013F4F5A97 C:\src\repos\binutils-gdb.git\gdb\infrun.c:8420:23 [print_stop_location] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:8436:25 [print_stop_event(ui_out*, bool)] > 0x000000013F6630BD C:\src\repos\binutils-gdb.git\gdb\tui\tui-interp.c:99:19 [tui_on_normal_stop] > 0x000000013F4F6F4F c:\msys64\mingw64\x86_64-w64-mingw32\include\c++\11.2.0\bits\std_function.h:560:9 [std::function<void (bpstats*, int)>::operator()(bpstats*, int) const] > c:\src\repos\binutils-gdb.git\gdbsupport\observable.h:150:9 [gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const] > C:\src\repos\binutils-gdb.git\gdb\infrun.c:8705:40 [normal_stop()] > 0x000000013F502B42 C:\src\repos\binutils-gdb.git\gdb\infrun.c:4157:29 [fetch_inferior_event()] > 0x000000013F3885FA C:\src\repos\binutils-gdb.git\gdb\async-event.c:335:31 [check_async_event_handlers()] > 0x000000013F795901 C:\src\repos\binutils-gdb.git\gdbsupport\event-loop.cc:216:37 [gdb_do_one_event()] > 0x000000013F64CD5B C:\src\repos\binutils-gdb.git\gdb\top.c:529:27 [wait_sync_command_done()] > 0x000000013F64D650 C:\src\repos\binutils-gdb.git\gdb\top.c:546:28 [maybe_wait_sync_command_done(int)] > C:\src\repos\binutils-gdb.git\gdb\top.c:687:36 [execute_command(char const*, int)] > 0x000000013F5213BB C:\src\repos\binutils-gdb.git\gdb\main.c:523:15 [catch_command_errors] > 0x000000013F5214E5 C:\src\repos\binutils-gdb.git\gdb\main.c:618:30 [execute_cmdargs] > 0x000000013F524693 C:\src\repos\binutils-gdb.git\gdb\main.c:1322:19 [captured_main_1] > 0x000000013F5250FC C:\src\repos\binutils-gdb.git\gdb\main.c:1343:19 [captured_main] > C:\src\repos\binutils-gdb.git\gdb\main.c:1368:21 [gdb_main(captured_main_args*)] > 0x000000013FA3C146 C:\src\repos\binutils-gdb.git\gdb\gdb.c:32:19 [main] > 0x000000013F351430 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:345:15 [__tmainCRTStartup] > 0x000000013F3515B5 C:\gcc\src\mingw-w64-v8.0.2\mingw-w64-crt\crt\crtexe.c:220:9 [mainCRTStartup]
Should I not be even attempting to use gdb.parse_and_eval('$__cat->name()') like that in a printer? Is there a better way to call a virtual member function given a pointer to a polymorphic object?
(In reply to Jonathan Wakely from comment #2) > Should I not be even attempting to use gdb.parse_and_eval('$__cat->name()') > like that in a printer? Is there a better way to call a virtual member > function given a pointer to a polymorphic object? If you need to call it, then I don't think there is a better way. I would only use a function call in a pretty printer if there is no way to avoid it, even more so because it wouldn't work for core files.
(In reply to Jonathan Wakely from comment #2) > Should I not be even attempting to use gdb.parse_and_eval('$__cat->name()') > like that in a printer? Is there a better way to call a virtual member > function given a pointer to a polymorphic object? I agree with Hannes: you should ideally not call a function in the pretty printer so that it works with core files. But it's still a GDB bug, if someone chooses to do it, it should work.
OK, thanks. I suppose I could just use the class name instead of calling the name() member. I think my preference would be to try to call the function, and if that returns a char* then use that, and if it fails (e.g. because there's no inferior process, just a core) then use the class name. But of course to gracefully find out if calling the function is possible, it needs to not crash :-) For the std:: error categories I can actually avoid calling the name() function, because GDB can look up the address of the private symbol and compare the _M_cat pointer to that. gdb.parse_and_eval('_ZN12_GLOBAL__N_124system_category_instanceE.obj').address But for user-defined custom categories, I'd like to be able to print the name. I'll see what I can do to avoid calling the function. Thanks for the guidance.
I have managed to reproduce the crash without using the pretty printer. In fact, all I need to reproduce is: gdb -q ec -ex start -ex n -ex s -ex bt and it crashes using backtrace, up or finish. What I found while trying to debug this is that there is a corruption in the linked list, creating the following entry: 1: *this_frame = {level = 0, pspace = 0x0, aspace = 0x26b6d00, prologue_cache = 0x0, unwind = 0x0, prev_arch = {p = false, arch = 0x0}, prev_pc = {status = CC_UNKNOWN, masked = false, value = 0x0}, prev_func = {addr = 0x40113c, status = CC_VALUE}, this_id = {p = frame_id_status::COMPUTED, value = {stack_addr = 0x0, code_addr = 0x0, special_addr = 0x0, stack_status = FID_STACK_SENTINEL, code_addr_p = 0, special_addr_p = 1, artificial_depth = 0}}, base = 0x0, base_cache = 0x0, next = 0x288fee0, prev_p = true, prev = 0x288ffb0, stop_reason = UNWIND_NO_REASON, stop_string = 0x0} (top-gdb) p this_frame $2 = (frame_info *) 0x288fee0 I haven't tracked down where this is happening, but my guess is somewhere during the step process.
The master branch has been updated by Bruno Larsen <blarsen@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=daaf7acf47a12d10459060dca5500b63273cd683 commit daaf7acf47a12d10459060dca5500b63273cd683 Author: Bruno Larsen <blarsen@redhat.com> Date: Tue Feb 22 11:44:44 2022 -0300 [gdb/testsuite] test a function call by hand from pretty printer The test case added here is testing the bug gdb/28856, where calling a function by hand from a pretty printer makes GDB crash. There are 6 mechanisms to trigger this crash in the current test, using the commands backtrace, up, down, finish, step and continue. Since the failure happens because of use-after-free (more details below) the tests will always have a chance of passing through sheer luck, but anecdotally they seem to fail all of the time. The reason GDB is crashing is a use-after-free problem. The above mentioned functions save a pointer to the current frame's information, then calls the pretty printer, and uses the saved pointer for different reasons, depending on the function. The issue happens because call_function_by_hand needs to reset the obstack to get the current frame, invalidating the saved pointer.
Created attachment 14034 [details] Test case This test case used to be in the tree (with some setup_kfails), but it still causes problems when GDB is built with ASan. I removed it from the tree and am attaching it here, so it can be merged back when we have a corresponding fix.
The master branch has been updated by Bruno Larsen <blarsen@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c29a6445a981cee5e8eebe3617ef5c049fd3409f commit c29a6445a981cee5e8eebe3617ef5c049fd3409f Author: Bruno Larsen <blarsen@redhat.com> Date: Mon Jul 25 14:06:37 2022 -0300 gdb/frame: Add reinflation method for frame_info_ptr Currently, despite having a smart pointer for frame_infos, GDB may attempt to use an invalidated frame_info_ptr, which would cause internal errors to happen. One such example has been documented as PR python/28856, that happened when printing frame arguments calls an inferior function. To avoid failures, the smart wrapper was changed to also cache the frame id, so the pointer can be reinflated later. For this to work, the frame-id stuff had to be moved to their own .h file, which is included by frame-info.h. Frame_id caching is done explicitly using the prepare_reinflate method. Caching is done manually so that only the pointers that need to be saved will be, and reinflating has to be done manually using the reinflate method because the get method and the -> operator must not change the internals of the class. Finally, attempting to reinflate when the pointer is being invalidated causes the following assertion errors: check_ptrace_stopped_lwp_gone: assertion `lp->stopped` failed. get_frame_pc: Assertion `frame->next != NULL` failed. As for performance concerns, my personal testing with `time make chec-perf GDB_PERFTEST_MODE=run` showed an actual reduction of around 10% of time running. This commit also adds a testcase that exercises the python/28856 bug with 7 different triggers, run, continue, step, backtrace, finish, up and down. Some of them can seem to be testing the same thing twice, but since this test relies on stale pointers, there is always a chance that GDB got lucky when testing, so better to test extra. Regression tested on x86_64, using both gcc and clang. Approved-by: Tom Tomey <tom@tromey.com>
The commit mentioned by cvs-commit fixes this issue.
*** Bug 24393 has been marked as a duplicate of this bug. ***
*** Bug 17437 has been marked as a duplicate of this bug. ***