OS: Debian GNU/Linux 10 (buster) Version: gdb-13.2 built from source against Python 3.7. $ gdb --batch -ex 'pi gdb.post_event(lambda : print("test"))' Fatal signal: Segmentation fault ----- Backtrace ----- 0x563e4c327527 gdb_internal_backtrace_1 ../../gdb/bt-utils.c:122 0x563e4c327527 _Z22gdb_internal_backtracev ../../gdb/bt-utils.c:168 0x563e4c44573a handle_fatal_signal ../../gdb/event-top.c:956 0x563e4c4457df handle_sigsegv ../../gdb/event-top.c:1029 0x7fb16addc72f ??? 0x7fb16af9bec9 ??? 0x7fb16af9c01b ??? Segmentation fault (core dumped) Stack trace as reported by gdb --args (with above cmd): ... #0 0x00007f47ac003ec9 in PyThreadState_New () from /usr/lib/x86_64-linux-gnu/libpython3.7m.so.1.0 #1 0x00007f47ac00401c in PyGILState_Ensure () from /usr/lib/x86_64-linux-gnu/libpython3.7m.so.1.0 #2 0x00005568cdefebff in gdbpy_gil::gdbpy_gil (this=<synthetic pointer>) at ../../gdb/python/python.c:265 #3 gdbpy_event::~gdbpy_event (this=0x5568cfa1c6d0, __in_chrg=<optimized out>) at ../../gdb/python/python.c:1022 #4 std::_Function_base::_Base_manager<gdbpy_event>::_M_destroy (__victim=...) at /usr/include/c++/8/bits/std_function.h:188 #5 std::_Function_base::_Base_manager<gdbpy_event>::_M_manager (__dest=..., __source=..., __op=<optimized out>) at /usr/include/c++/8/bits/std_function.h:212 #6 0x00005568cdf73fce in std::_Function_base::~_Function_base (this=0x5568cf8552f0, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/std_function.h:257 #7 std::function<void ()>::~function() (this=0x5568cf8552f0, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/std_function.h:370 #8 std::_Destroy<std::function<void ()> >(std::function<void ()>*) (__pointer=0x5568cf8552f0) at /usr/include/c++/8/bits/stl_construct.h:98 #9 std::_Destroy_aux<false>::__destroy<std::function<void ()>*>(std::function<void ()>*, std::function<void ()>*) (__last=<optimized out>, __first=0x5568cf8552f0) at /usr/include/c++/8/bits/stl_construct.h:108 #10 std::_Destroy<std::function<void ()>*>(std::function<void ()>*, std::function<void ()>*) (__last=<optimized out>, __first=<optimized out>) at /usr/include/c++/8/bits/stl_construct.h:137 #11 std::_Destroy<std::function<void ()>*, std::function<void ()> >(std::function<void ()>*, std::function<void ()>*, std::allocator<std::function<void ()> >&) (__last=0x5568cf855310, __first=<optimized out>) at /usr/include/c++/8/bits/stl_construct.h:206 #12 std::vector<std::function<void ()>, std::allocator<std::function<void ()> > >::~vector() (this=0x5568cf626c50 <runnables>, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/stl_vector.h:567 #13 0x00007f47ab8bcebc in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #14 0x00007f47ab8bcfea in exit () from /lib/x86_64-linux-gnu/libc.so.6 #15 0x00005568ce0533e2 in quit_force (exit_arg=<optimized out>, from_tty=from_tty@entry=0) at ../../gdb/top.c:1896 #16 0x00005568cdddc3f3 in captured_main_1 (context=context@entry=0x7fffb9066670) at ../../gdb/main.c:1311 #17 0x00005568cdddcf7b in captured_main (data=data@entry=0x7fffb9066670) at ../../gdb/main.c:1320 #18 gdb_main (args=args@entry=0x7fffb9066690) at ../../gdb/main.c:1345 #19 0x00005568cda7ca8b in main (argc=<optimized out>, argv=<optimized out>) at ../../gdb/gdb.c:32 Note: it does not crash when run without '--batch' in interactive mode, which is the expected behavior.
Tentative fix, similar to what is done for finalize_values: ... diff --git a/gdb/run-on-main-thread.c b/gdb/run-on-main-thread.c index 2d40048de56..e06b751f221 100644 --- a/gdb/run-on-main-thread.c +++ b/gdb/run-on-main-thread.c @@ -33,6 +33,14 @@ static struct serial_event *runnable_event; static std::vector<std::function<void ()>> runnables; +/* See run-on-main-thread.h. */ + +void +finalize_runnables (void) +{ + runnables.clear (); +} + #if CXX_STD_THREAD /* Mutex to hold when handling RUNNABLE_EVENT or RUNNABLES. */ diff --git a/gdb/run-on-main-thread.h b/gdb/run-on-main-thread.h index 4f370dddb9e..27eaff3df72 100644 --- a/gdb/run-on-main-thread.h +++ b/gdb/run-on-main-thread.h @@ -29,4 +29,8 @@ extern void run_on_main_thread (std::function<void ()> &&); extern bool is_main_thread (); +/* Destroy the runnables currently allocated. This is called when GDB is + exiting (e.g., on quit_force). */ +extern void finalize_runnables (); + #endif /* GDB_RUN_ON_MAIN_THREAD_H */ diff --git a/gdb/top.c b/gdb/top.c index fb15c719564..221ef329951 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -74,6 +74,7 @@ #include "cli-out.h" #include "tracepoint.h" #include "inf-loop.h" +#include "run-on-main-thread.h" #if defined(TUI) # include "tui/tui.h" @@ -1813,6 +1814,10 @@ quit_force (int *exit_arg, int from_tty) runtime, which is finalized via a final cleanup. */ finalize_values (); + /* Likewise, destroy any runnables currenctly allocated now. The destructor + of gdbpy_event calls into the Python runtime. */ + finalize_runnables (); + /* Do any final cleanups before exiting. */ try { ... With this patch, we have: ... $ gdb --batch -ex 'pi gdb.post_event(lambda : print("test"))' $ ...
See also PR31306.
I have a fix that's the same idea as comment#1 but written in a slightly different way.
The master branch has been updated by Tom Tromey <tromey@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6313c05640cf6e2f6b1b1b8e66789b34b45f19c7 commit 6313c05640cf6e2f6b1b1b8e66789b34b45f19c7 Author: Tom Tromey <tromey@adacore.com> Date: Fri Feb 23 13:26:02 2024 -0700 Add final cleanup for runnables This changes run-on-main-thread.c to clear 'runnables' in a final cleanup. This avoids an issue where a pending runnable could require Python, but be run after the Python interpreter was finalized. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31172
Fixed.