Skip to content

Commit

Permalink
gh-128400: Stop-the-world when manually calling faulthandler (GH-12…
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeroIntensity authored Jan 2, 2025
1 parent a626f9a commit c9356fe
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 1 deletion.
30 changes: 29 additions & 1 deletion Lib/test/test_faulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
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
Expand Down Expand Up @@ -896,6 +896,34 @@ def test_cancel_later_without_dump_traceback_later(self):
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()
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit c9356fe

Please sign in to comment.