0007-Fix-Python3.9-related-runtime-problems.patch 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. From 51ef4f6ec819259d4a57fa4155ee78700918f8ff Mon Sep 17 00:00:00 2001
  2. From: Kevin Buettner <kevinb@redhat.com>
  3. Date: Wed, 27 May 2020 20:05:40 -0700
  4. Subject: [PATCH] Fix Python3.9 related runtime problems
  5. Python3.9b1 is now available on Rawhide. GDB w/ Python 3.9 support
  6. can be built using the configure switch -with-python=/usr/bin/python3.9.
  7. Attempting to run gdb/Python3.9 segfaults on startup:
  8. #0 0x00007ffff7b0582c in PyEval_ReleaseLock () from /lib64/libpython3.9.so.1.0
  9. #1 0x000000000069ccbf in do_start_initialization ()
  10. at worktree-test1/gdb/python/python.c:1789
  11. #2 _initialize_python ()
  12. at worktree-test1/gdb/python/python.c:1877
  13. #3 0x00000000007afb0a in initialize_all_files () at init.c:237
  14. ...
  15. Consulting the the documentation...
  16. https://docs.python.org/3/c-api/init.html
  17. ...we find that PyEval_ReleaseLock() has been deprecated since version
  18. 3.2. It recommends using PyEval_SaveThread or PyEval_ReleaseThread()
  19. instead. In do_start_initialization, in gdb/python/python.c, we
  20. can replace the calls to PyThreadState_Swap() and PyEval_ReleaseLock()
  21. with a single call to PyEval_SaveThread. (Thanks to Keith Seitz
  22. for working this out.)
  23. With that in place, GDB gets a little bit further. It still dies
  24. on startup, but the backtrace is different:
  25. #0 0x00007ffff7b04306 in PyOS_InterruptOccurred ()
  26. from /lib64/libpython3.9.so.1.0
  27. #1 0x0000000000576e86 in check_quit_flag ()
  28. at worktree-test1/gdb/extension.c:776
  29. #2 0x0000000000576f8a in set_active_ext_lang (now_active=now_active@entry=0x983c00 <extension_language_python>)
  30. at worktree-test1/gdb/extension.c:705
  31. #3 0x000000000069d399 in gdbpy_enter::gdbpy_enter (this=0x7fffffffd2d0,
  32. gdbarch=0x0, language=0x0)
  33. at worktree-test1/gdb/python/python.c:211
  34. #4 0x0000000000686e00 in python_new_inferior (inf=0xddeb10)
  35. at worktree-test1/gdb/python/py-inferior.c:251
  36. #5 0x00000000005d9fb9 in std::function<void (inferior*)>::operator()(inferior*) const (__args#0=<optimized out>, this=0xccad20)
  37. at /usr/include/c++/10/bits/std_function.h:617
  38. #6 gdb::observers::observable<inferior*>::notify (args#0=0xddeb10,
  39. this=<optimized out>)
  40. at worktree-test1/gdb/../gdbsupport/observable.h:106
  41. #7 add_inferior_silent (pid=0)
  42. at worktree-test1/gdb/inferior.c:113
  43. #8 0x00000000005dbcb8 in initialize_inferiors ()
  44. at worktree-test1/gdb/inferior.c:947
  45. ...
  46. We checked with some Python Developers and were told that we should
  47. acquire the GIL prior to calling any Python C API function. We
  48. definitely don't have the GIL for calls of PyOS_InterruptOccurred().
  49. I moved class_gdbpy_gil earlier in the file and use it in
  50. gdbpy_check_quit_flag() to acquire (and automatically release) the
  51. GIL.
  52. With those changes in place, I was able to run to a GDB prompt. But,
  53. when trying to quit, it segfaulted again due to due to some other
  54. problems with gdbpy_check_quit_flag():
  55. Thread 1 "gdb" received signal SIGSEGV, Segmentation fault.
  56. 0x00007ffff7bbab0c in new_threadstate () from /lib64/libpython3.9.so.1.0
  57. (top-gdb) bt 8
  58. #0 0x00007ffff7bbab0c in new_threadstate () from /lib64/libpython3.9.so.1.0
  59. #1 0x00007ffff7afa5ea in PyGILState_Ensure.cold ()
  60. from /lib64/libpython3.9.so.1.0
  61. #2 0x000000000069b58c in gdbpy_gil::gdbpy_gil (this=<synthetic pointer>)
  62. at worktree-test1/gdb/python/python.c:278
  63. #3 gdbpy_check_quit_flag (extlang=<optimized out>)
  64. at worktree-test1/gdb/python/python.c:278
  65. #4 0x0000000000576e96 in check_quit_flag ()
  66. at worktree-test1/gdb/extension.c:776
  67. #5 0x000000000057700c in restore_active_ext_lang (previous=0xe9c050)
  68. at worktree-test1/gdb/extension.c:729
  69. #6 0x000000000088913a in do_my_cleanups (
  70. pmy_chain=0xc31870 <final_cleanup_chain>,
  71. old_chain=0xae5720 <sentinel_cleanup>)
  72. at worktree-test1/gdbsupport/cleanups.cc:131
  73. #7 do_final_cleanups ()
  74. at worktree-test1/gdbsupport/cleanups.cc:143
  75. In this case, we're trying to call a Python C API function after
  76. Py_Finalize() has been called from finalize_python(). I made
  77. finalize_python set gdb_python_initialized to false and then cause
  78. check_quit_flag() to return early when it's false.
  79. With these changes in place, GDB seems to be working again with
  80. Python3.9b1. I think it likely that there are other problems lurking.
  81. I wouldn't be surprised to find that there are other calls into Python
  82. where we don't first make sure that we have the GIL. Further changes
  83. may well be needed.
  84. I see no regressions testing on Rawhide using a GDB built with the
  85. default Python version (3.8.3) versus one built using Python 3.9b1.
  86. I've also tested on Fedora 28, 29, 30, 31, and 32 (all x86_64) using
  87. the default (though updated) system installed versions of Python on
  88. those OSes. This means that I've tested against Python versions
  89. 2.7.15, 2.7.17, 2.7.18, 3.7.7, 3.8.2, and 3.8.3. In each case GDB
  90. still builds without problem and shows no regressions after applying
  91. this patch.
  92. gdb/ChangeLog:
  93. 2020-MM-DD Kevin Buettner <kevinb@redhat.com>
  94. Keith Seitz <keiths@redhat.com>
  95. * python/python.c (do_start_initialization): For Python 3.9 and
  96. later, call PyEval_SaveThread instead of PyEval_ReleaseLock.
  97. (class gdbpy_gil): Move to earlier in file.
  98. (finalize_python): Set gdb_python_initialized.
  99. (gdbpy_check_quit_flag): Acquire GIL via gdbpy_gil. Return early
  100. when not initialized.
  101. [import into Buildroot, removing ChangeLog change to avoid conflict]
  102. Signed-off-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
  103. ---
  104. gdb/python/python.c | 32 ++++++++++++++++++++++++++++++--
  105. 1 file changed, 30 insertions(+), 2 deletions(-)
  106. diff --git a/gdb/python/python.c b/gdb/python/python.c
  107. index c23db2c1261..0b77354630e 100644
  108. --- a/gdb/python/python.c
  109. +++ b/gdb/python/python.c
  110. @@ -235,6 +235,30 @@ gdbpy_enter::~gdbpy_enter ()
  111. restore_active_ext_lang (m_previous_active);
  112. }
  113. +/* A helper class to save and restore the GIL, but without touching
  114. + the other globals that are handled by gdbpy_enter. */
  115. +
  116. +class gdbpy_gil
  117. +{
  118. +public:
  119. +
  120. + gdbpy_gil ()
  121. + : m_state (PyGILState_Ensure ())
  122. + {
  123. + }
  124. +
  125. + ~gdbpy_gil ()
  126. + {
  127. + PyGILState_Release (m_state);
  128. + }
  129. +
  130. + DISABLE_COPY_AND_ASSIGN (gdbpy_gil);
  131. +
  132. +private:
  133. +
  134. + PyGILState_STATE m_state;
  135. +};
  136. +
  137. /* Set the quit flag. */
  138. static void
  139. @@ -248,6 +272,10 @@ gdbpy_set_quit_flag (const struct extension_language_defn *extlang)
  140. static int
  141. gdbpy_check_quit_flag (const struct extension_language_defn *extlang)
  142. {
  143. + if (!gdb_python_initialized)
  144. + return 0;
  145. +
  146. + gdbpy_gil gil;
  147. return PyOS_InterruptOccurred ();
  148. }
  149. @@ -1573,6 +1601,7 @@ finalize_python (void *ignore)
  150. Py_Finalize ();
  151. + gdb_python_initialized = false;
  152. restore_active_ext_lang (previous_active);
  153. }
  154. @@ -1736,8 +1765,7 @@ do_start_initialization ()
  155. return false;
  156. /* Release the GIL while gdb runs. */
  157. - PyThreadState_Swap (NULL);
  158. - PyEval_ReleaseLock ();
  159. + PyEval_SaveThread ();
  160. make_final_cleanup (finalize_python, NULL);
  161. --
  162. 2.31.1