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

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