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

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