https://github.com/python/cpython/commit/ebadfd1039a321a142e0e09e040bf8e724bb5905
commit: ebadfd1039a321a142e0e09e040bf8e724bb5905
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: colesbury <[email protected]>
date: 2025-01-02T19:21:16Z
summary:

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

(cherry picked from commit c9356feef28e6dfc4dc32830d3427a5ae0e426e2)

Co-authored-by: Peter Bierma <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-01-02-13-05-16.gh-issue-128400.5N43fF.rst
M Lib/test/test_faulthandler.py
M Modules/faulthandler.c

diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index 60815be96e14eb..fd56dee5d842ac 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -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
@@ -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()
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
index 00000000000000..4033dea4eaf7bf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-01-02-13-05-16.gh-issue-128400.5N43fF.rst
@@ -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.
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index b62362f277797e..2d16028a5232d0 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to