Blame SOURCES/gdb-rhbz1829702-fix-python39.patch

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