https://github.com/python/cpython/commit/6e983938834a8b6c7043369b3c5de2b5d2084ea4
commit: 6e983938834a8b6c7043369b3c5de2b5d2084ea4
branch: main
author: Jiucheng(Oliver) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-07-24T10:11:08+05:30
summary:

gh-153176: Fix destroy_interpreter() test helper clearing a non-current thread 
state (#153307)

Co-authored-by: Kumar Aditya <[email protected]>
Co-authored-by: Xiaowei Lu <[email protected]>

files:
A Lib/test/test_free_threading/test_interpreters.py
M Modules/_testinternalcapi.c

diff --git a/Lib/test/test_free_threading/test_interpreters.py 
b/Lib/test/test_free_threading/test_interpreters.py
new file mode 100644
index 00000000000000..a9a432fae16b1e
--- /dev/null
+++ b/Lib/test/test_free_threading/test_interpreters.py
@@ -0,0 +1,29 @@
+import textwrap
+import unittest
+
+from test.support import import_helper, script_helper
+
+
+# Make sure _testinternalcapi is available before running the test.
+import_helper.import_module('_testinternalcapi')
+
+
+class InterpreterTeardownTests(unittest.TestCase):
+    def test_destroy_subinterpreter_does_not_abort(self):
+        # gh-153176: destroy_interpreter(basic=True) used to call
+        # PyThreadState_Clear() on a non-current thread state, which on a
+        # free-threaded debug build reclaimed mimalloc pages into a heap not
+        # owned by the current thread and aborted the process.  Run the
+        # reproduction in a subprocess so that a regression surfaces as a
+        # non-zero exit / SIGABRT instead of killing the test runner.
+        script = textwrap.dedent("""
+            import _testinternalcapi
+
+            interpid = _testinternalcapi.create_interpreter()
+            _testinternalcapi.destroy_interpreter(interpid, basic=True)
+        """)
+        script_helper.assert_python_ok('-c', script)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 166397a72da3aa..e9950bb232431c 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -2312,8 +2312,7 @@ destroy_interpreter(PyObject *self, PyObject *args, 
PyObject *kwargs)
         }
         t2 = PyThreadState_New(interp);
         prev = PyThreadState_Swap(t2);
-        PyThreadState_Clear(t1);
-        PyThreadState_Delete(t1);
+        // t1 is deliberately left alive; Py_EndInterpreter() must clean it up.
         Py_EndInterpreter(t2);
         PyThreadState_Swap(prev);
     }

_______________________________________________
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