https://github.com/python/cpython/commit/6959d94c0163fa07bfcf5ee4aac4579005edfeef
commit: 6959d94c0163fa07bfcf5ee4aac4579005edfeef
branch: 3.13
author: Cody Maloney <[email protected]>
committer: Yhg1s <[email protected]>
date: 2026-09-29T23:24:31+02:00
summary:

[3.13] gh-154175: Fetch _PY_GIL_DROP_REQUEST_BIT under GIL (#157013)

gh-154175: Fetch _PY_GIL_DROP_REQUEST_BIT under GIL

Once the GIL is released the tstate may be freed which shows up as ASAN
and TSAN failures in test_io with daemon threads. Check the bit before
dropping the GIL so the tstate is guaranteed to still be allocated.

Remove the TSAN suppressions which were added for 3.13 as this should
fix this case.

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-09-05-16-24-52.gh-issue-154175.YJon4M.rst
M Python/ceval_gil.c
M Tools/tsan/suppressions.txt
M Tools/tsan/suppressions_free_threading.txt

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-05-16-24-52.gh-issue-154175.YJon4M.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-05-16-24-52.gh-issue-154175.YJon4M.rst
new file mode 100644
index 000000000000000..682cfca7d1c7212
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-05-16-24-52.gh-issue-154175.YJon4M.rst
@@ -0,0 +1,4 @@
+Move GIL drop request bit fetching to live under the :term:`GIL` so the
+:c:type:`PyThreadState` it accesses is guaranteed not to be deallocated.
+Deallocation could occur when a daemon thread was shutting down after the
+main thread.
diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c
index a1433e5b25fea4b..fb9571247d68c27 100644
--- a/Python/ceval_gil.c
+++ b/Python/ceval_gil.c
@@ -246,11 +246,16 @@ drop_gil(PyInterpreterState *interp, PyThreadState 
*tstate, int final_release)
         Py_FatalError("drop_gil: GIL is not locked");
     }
 
+    int drop_requested = 0;
     if (!final_release) {
         /* Sub-interpreter support: threads might have been switched
            under our feet using PyThreadState_Swap(). Fix the GIL last
            holder variable so that our heuristics work. */
         _Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate);
+
+        /* Checked here as tstate may freed outside gil. */
+        drop_requested = _Py_eval_breaker_bit_is_set(tstate,
+                                                     _PY_GIL_DROP_REQUEST_BIT);
     }
 
     drop_gil_impl(tstate, gil);
@@ -262,8 +267,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate, 
int final_release)
        crash.  We can use final_release to indicate the thread is done with the
        GIL, and that's the only time we might delete the interpreter.  See
        https://github.com/python/cpython/issues/104341. */
-    if (!final_release &&
-        _Py_eval_breaker_bit_is_set(tstate, _PY_GIL_DROP_REQUEST_BIT)) {
+    if (!final_release && drop_requested) {
         MUTEX_LOCK(gil->switch_mutex);
         /* Not switched yet => wait */
         if (((PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) 
== tstate)
diff --git a/Tools/tsan/suppressions.txt b/Tools/tsan/suppressions.txt
index de89a41f4202353..22ba9d6ba2ab4de 100644
--- a/Tools/tsan/suppressions.txt
+++ b/Tools/tsan/suppressions.txt
@@ -3,8 +3,5 @@
 race:get_allocator_unlocked
 race:set_allocator_unlocked
 
-# gh-124878: race condition when interpreter finalized while daemon thread runs
-race:free_threadstate
-
 # https://gist.github.com/mpage/daaf32b39180c1989572957b943eb665
 thread:pthread_create
diff --git a/Tools/tsan/suppressions_free_threading.txt 
b/Tools/tsan/suppressions_free_threading.txt
index da30d7020d1202a..947ee9f80b07c48 100644
--- a/Tools/tsan/suppressions_free_threading.txt
+++ b/Tools/tsan/suppressions_free_threading.txt
@@ -18,9 +18,6 @@ race:set_allocator_unlocked
 # https://gist.github.com/swtaarrs/8e0e365e1d9cecece3269a2fb2f2b8b8
 race:sock_recv_impl
 
-# gh-124878: race condition when interpreter finalized while daemon thread runs
-race:free_threadstate
-
 
 # These warnings trigger directly in a CPython function.
 

_______________________________________________
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