[3.13] gh-128400: Stop-the-world when manually calling faulthandler (GH-128422) (GH-128423)

(cherry picked from commit c9356feef2)

Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-01-02 20:21:16 +01:00 committed by GitHub
parent fa6c48e4b3
commit ebadfd1039
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 36 additions and 1 deletions

View file

@ -7,7 +7,7 @@ import signal
import subprocess
import sys
from test import support
from test.support import os_helper, script_helper, is_android, MS_WINDOWS
from test.support import os_helper, script_helper, is_android, MS_WINDOWS, threading_helper
import tempfile
import unittest
from textwrap import dedent
@ -896,6 +896,34 @@ class FaultHandlerTests(unittest.TestCase):
self.assertEqual(output, [])
self.assertEqual(exitcode, 0)
@threading_helper.requires_working_threading()
@unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful if the GIL is disabled")
def test_free_threaded_dump_traceback(self):
# gh-128400: Other threads need to be paused to invoke faulthandler
code = dedent("""
import faulthandler
from threading import Thread, Event
class Waiter(Thread):
def __init__(self):
Thread.__init__(self)
self.running = Event()
self.stop = Event()
def run(self):
self.running.set()
self.stop.wait()
for _ in range(100):
waiter = Waiter()
waiter.start()
waiter.running.wait()
faulthandler.dump_traceback(all_threads=True)
waiter.stop.set()
waiter.join()
""")
_, exitcode = self.get_output(code)
self.assertEqual(exitcode, 0)
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1,2 @@
Fix crash when using :func:`faulthandler.dump_traceback` while other threads
are active on the :term:`free threaded <free threading>` build.

View file

@ -237,7 +237,12 @@ faulthandler_dump_traceback_py(PyObject *self,
return NULL;
if (all_threads) {
PyInterpreterState *interp = _PyInterpreterState_GET();
/* gh-128400: Accessing other thread states while they're running
* isn't safe if those threads are running. */
_PyEval_StopTheWorld(interp);
errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate);
_PyEval_StartTheWorld(interp);
if (errmsg != NULL) {
PyErr_SetString(PyExc_RuntimeError, errmsg);
return NULL;