Skip to content

Commit 93c5342

Browse files
committed
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.
1 parent 2fa4e32 commit 93c5342

4 files changed

Lines changed: 10 additions & 8 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Move GIL drop request bit fetching to live under the :term:`GIL` so the
2+
:c:type:`PyThreadState` it accesses is guaranteed not to be deallocated.
3+
Deallocation could occur when a daemon thread was shutting down after the
4+
main thread.

Python/ceval_gil.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,16 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate, int final_release)
246246
Py_FatalError("drop_gil: GIL is not locked");
247247
}
248248

249+
int drop_requested = 0;
249250
if (!final_release) {
250251
/* Sub-interpreter support: threads might have been switched
251252
under our feet using PyThreadState_Swap(). Fix the GIL last
252253
holder variable so that our heuristics work. */
253254
_Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate);
255+
256+
/* Checked here as tstate may freed outside gil. */
257+
drop_requested = _Py_eval_breaker_bit_is_set(tstate,
258+
_PY_GIL_DROP_REQUEST_BIT);
254259
}
255260

256261
drop_gil_impl(tstate, gil);
@@ -262,8 +267,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate, int final_release)
262267
crash. We can use final_release to indicate the thread is done with the
263268
GIL, and that's the only time we might delete the interpreter. See
264269
https://github.com/python/cpython/issues/104341. */
265-
if (!final_release &&
266-
_Py_eval_breaker_bit_is_set(tstate, _PY_GIL_DROP_REQUEST_BIT)) {
270+
if (!final_release && drop_requested) {
267271
MUTEX_LOCK(gil->switch_mutex);
268272
/* Not switched yet => wait */
269273
if (((PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) == tstate)

Tools/tsan/suppressions.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,5 @@
33
race:get_allocator_unlocked
44
race:set_allocator_unlocked
55

6-
# gh-124878: race condition when interpreter finalized while daemon thread runs
7-
race:free_threadstate
8-
96
# https://gist.github.com/mpage/daaf32b39180c1989572957b943eb665
107
thread:pthread_create

Tools/tsan/suppressions_free_threading.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ race:set_allocator_unlocked
1818
# https://gist.github.com/swtaarrs/8e0e365e1d9cecece3269a2fb2f2b8b8
1919
race:sock_recv_impl
2020

21-
# gh-124878: race condition when interpreter finalized while daemon thread runs
22-
race:free_threadstate
23-
2421

2522
# These warnings trigger directly in a CPython function.
2623

0 commit comments

Comments
 (0)