]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-128400: Stop-the-world when manually calling `faulthandler` (GH-128422)
authorPeter Bierma <zintensitydev@gmail.com>
Thu, 2 Jan 2025 18:56:01 +0000 (13:56 -0500)
committerGitHub <noreply@github.com>
Thu, 2 Jan 2025 18:56:01 +0000 (13:56 -0500)
Lib/test/test_faulthandler.py
Misc/NEWS.d/next/Library/2025-01-02-13-05-16.gh-issue-128400.5N43fF.rst [new file with mode: 0644]
Modules/faulthandler.c

index 60815be96e14eb69342bb5afbe13916f6e70c0ee..fd56dee5d842ac3b3fa9ba1765429013efe4ba85 100644 (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()
diff --git a/Misc/NEWS.d/next/Library/2025-01-02-13-05-16.gh-issue-128400.5N43fF.rst b/Misc/NEWS.d/next/Library/2025-01-02-13-05-16.gh-issue-128400.5N43fF.rst
new file mode 100644 (file)
index 0000000..4033dea
--- /dev/null
@@ -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.
index b62362f277797e4e31beb1742d0b65e9ef3f0ac0..2d16028a5232d0cb1ff76a85406059cdcd1af98e 100644 (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;