From c20726b88f97436cf06d8a7c8b71844c1127e0c6 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Mon, 12 Oct 2020 14:47:38 -0400 Subject: [PATCH] gdb: patch for Python 3.9 compatibility Thanks to q66. --- srcpkgs/gdb/patches/py39.patch | 224 +++++++++++++++++++++++++++++++++ srcpkgs/gdb/template | 2 +- 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 srcpkgs/gdb/patches/py39.patch diff --git a/srcpkgs/gdb/patches/py39.patch b/srcpkgs/gdb/patches/py39.patch new file mode 100644 index 00000000000..d4eef5633a9 --- /dev/null +++ b/srcpkgs/gdb/patches/py39.patch @@ -0,0 +1,224 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Keith Seitz +Date: Thu, 4 Jun 2020 17:16:48 -0700 +Subject: gdb-rhbz1829702-fix-python39.patch + +;; Backport "Fix Python 3.9 related runtime problems" +;; Kevin Buettner and Keith Seitz + +commit c47bae859a5af0d95224d90000df0e529f7c5aa0 +Author: Kevin Buettner +Date: Wed May 27 20:05:40 2020 -0700 + + Fix Python3.9 related runtime problems + + Python3.9b1 is now available on Rawhide. GDB w/ Python 3.9 support + can be built using the configure switch -with-python=/usr/bin/python3.9. + + Attempting to run gdb/Python3.9 segfaults on startup: + + #0 0x00007ffff7b0582c in PyEval_ReleaseLock () from /lib64/libpython3.9 +.so.1.0 + #1 0x000000000069ccbf in do_start_initialization () + at worktree-test1/gdb/python/python.c:1789 + #2 _initialize_python () + at worktree-test1/gdb/python/python.c:1877 + #3 0x00000000007afb0a in initialize_all_files () at init.c:237 + ... + + Consulting the the documentation... + + https://docs.python.org/3/c-api/init.html + + ...we find that PyEval_ReleaseLock() has been deprecated since version + 3.2. It recommends using PyEval_SaveThread or PyEval_ReleaseThread() + instead. In do_start_initialization, in gdb/python/python.c, we + can replace the calls to PyThreadState_Swap() and PyEval_ReleaseLock() + with a single call to PyEval_SaveThread. (Thanks to Keith Seitz + for working this out.) + + With that in place, GDB gets a little bit further. It still dies + on startup, but the backtrace is different: + + #0 0x00007ffff7b04306 in PyOS_InterruptOccurred () + from /lib64/libpython3.9.so.1.0 + #1 0x0000000000576e86 in check_quit_flag () + at worktree-test1/gdb/extension.c:776 + #2 0x0000000000576f8a in set_active_ext_lang (now_active=now_active@entry=0x983c00 ) + at worktree-test1/gdb/extension.c:705 + #3 0x000000000069d399 in gdbpy_enter::gdbpy_enter (this=0x7fffffffd2d0, + gdbarch=0x0, language=0x0) + at worktree-test1/gdb/python/python.c:211 + #4 0x0000000000686e00 in python_new_inferior (inf=0xddeb10) + at worktree-test1/gdb/python/py-inferior.c:251 + #5 0x00000000005d9fb9 in std::function::operator()(inferior*) const (__args#0=, this=0xccad20) + at /usr/include/c++/10/bits/std_function.h:617 + #6 gdb::observers::observable::notify (args#0=0xddeb10, + this=) + at worktree-test1/gdb/../gdbsupport/observable.h:106 + #7 add_inferior_silent (pid=0) + at worktree-test1/gdb/inferior.c:113 + #8 0x00000000005dbcb8 in initialize_inferiors () + at worktree-test1/gdb/inferior.c:947 + ... + + We checked with some Python Developers and were told that we should + acquire the GIL prior to calling any Python C API function. We + definitely don't have the GIL for calls of PyOS_InterruptOccurred(). + + I moved class_gdbpy_gil earlier in the file and use it in + gdbpy_check_quit_flag() to acquire (and automatically release) the + GIL. + + With those changes in place, I was able to run to a GDB prompt. But, + when trying to quit, it segfaulted again due to due to some other + problems with gdbpy_check_quit_flag(): + + Thread 1 "gdb" received signal SIGSEGV, Segmentation fault. + 0x00007ffff7bbab0c in new_threadstate () from /lib64/libpython3.9.so.1.0 + (top-gdb) bt 8 + #0 0x00007ffff7bbab0c in new_threadstate () from /lib64/libpython3.9.so.1.0 + #1 0x00007ffff7afa5ea in PyGILState_Ensure.cold () + from /lib64/libpython3.9.so.1.0 + #2 0x000000000069b58c in gdbpy_gil::gdbpy_gil (this=) + at worktree-test1/gdb/python/python.c:278 + #3 gdbpy_check_quit_flag (extlang=) + at worktree-test1/gdb/python/python.c:278 + #4 0x0000000000576e96 in check_quit_flag () + at worktree-test1/gdb/extension.c:776 + #5 0x000000000057700c in restore_active_ext_lang (previous=0xe9c050) + at worktree-test1/gdb/extension.c:729 + #6 0x000000000088913a in do_my_cleanups ( + pmy_chain=0xc31870 , + old_chain=0xae5720 ) + at worktree-test1/gdbsupport/cleanups.cc:131 + #7 do_final_cleanups () + at worktree-test1/gdbsupport/cleanups.cc:143 + + In this case, we're trying to call a Python C API function after + Py_Finalize() has been called from finalize_python(). I made + finalize_python set gdb_python_initialized to false and then cause + check_quit_flag() to return early when it's false. + + With these changes in place, GDB seems to be working again with + Python3.9b1. I think it likely that there are other problems lurking. + I wouldn't be surprised to find that there are other calls into Python + where we don't first make sure that we have the GIL. Further changes + may well be needed. + + I see no regressions testing on Rawhide using a GDB built with the + default Python version (3.8.3) versus one built using Python 3.9b1. + + I've also tested on Fedora 28, 29, 30, 31, and 32 (all x86_64) using + the default (though updated) system installed versions of Python on + those OSes. This means that I've tested against Python versions + 2.7.15, 2.7.17, 2.7.18, 3.7.7, 3.8.2, and 3.8.3. In each case GDB + still builds without problem and shows no regressions after applying + this patch. + + gdb/ChangeLog: + + 2020-MM-DD Kevin Buettner + Keith Seitz + + * python/python.c (do_start_initialization): For Python 3.9 and + later, call PyEval_SaveThread instead of PyEval_ReleaseLock. + (class gdbpy_gil): Move to earlier in file. + (finalize_python): Set gdb_python_initialized. + (gdbpy_check_quit_flag): Acquire GIL via gdbpy_gil. Return early + when not initialized. + +diff --git a/gdb/python/python.c b/gdb/python/python.c +--- a/gdb/python/python.c ++++ b/gdb/python/python.c +@@ -234,6 +234,30 @@ gdbpy_enter::~gdbpy_enter () + PyGILState_Release (m_state); + } + ++/* A helper class to save and restore the GIL, but without touching ++ the other globals that are handled by gdbpy_enter. */ ++ ++class gdbpy_gil ++{ ++public: ++ ++ gdbpy_gil () ++ : m_state (PyGILState_Ensure ()) ++ { ++ } ++ ++ ~gdbpy_gil () ++ { ++ PyGILState_Release (m_state); ++ } ++ ++ DISABLE_COPY_AND_ASSIGN (gdbpy_gil); ++ ++private: ++ ++ PyGILState_STATE m_state; ++}; ++ + /* Set the quit flag. */ + + static void +@@ -247,6 +271,10 @@ gdbpy_set_quit_flag (const struct extension_language_defn *extlang) + static int + gdbpy_check_quit_flag (const struct extension_language_defn *extlang) + { ++ if (!gdb_python_initialized) ++ return 0; ++ ++ gdbpy_gil gil; + return PyOS_InterruptOccurred (); + } + +@@ -924,30 +952,6 @@ gdbpy_source_script (const struct extension_language_defn *extlang, + + /* Posting and handling events. */ + +-/* A helper class to save and restore the GIL, but without touching +- the other globals that are handled by gdbpy_enter. */ +- +-class gdbpy_gil +-{ +-public: +- +- gdbpy_gil () +- : m_state (PyGILState_Ensure ()) +- { +- } +- +- ~gdbpy_gil () +- { +- PyGILState_Release (m_state); +- } +- +- DISABLE_COPY_AND_ASSIGN (gdbpy_gil); +- +-private: +- +- PyGILState_STATE m_state; +-}; +- + /* A single event. */ + struct gdbpy_event + { +@@ -1548,6 +1552,7 @@ finalize_python (void *ignore) + + Py_Finalize (); + ++ gdb_python_initialized = false; + restore_active_ext_lang (previous_active); + } + +@@ -1720,8 +1725,7 @@ do_start_initialization () + return false; + + /* Release the GIL while gdb runs. */ +- PyThreadState_Swap (NULL); +- PyEval_ReleaseLock (); ++ PyEval_SaveThread (); + + make_final_cleanup (finalize_python, NULL); + diff --git a/srcpkgs/gdb/template b/srcpkgs/gdb/template index aad3abd497e..94b34123063 100644 --- a/srcpkgs/gdb/template +++ b/srcpkgs/gdb/template @@ -1,7 +1,7 @@ # Template file for 'gdb' pkgname=gdb version=9.2 -revision=3 +revision=4 build_style=gnu-configure pycompile_dirs="/usr/share/gdb/python" configure_args="--disable-werror --disable-nls --with-system-readline