https://github.com/python/cpython/commit/33d20199af65c741bdc908a968edd8dc179b6974
commit: 33d20199af65c741bdc908a968edd8dc179b6974
branch: main
author: Alex Turner <[email protected]>
committer: colesbury <[email protected]>
date: 2024-05-10T10:26:35-04:00
summary:

gh-117657: Fix QSBR race condition (#118843)

`_Py_qsbr_unregister` is called when the PyThreadState is already
detached, so the access to `tstate->qsbr` isn't safe without locking the
shared mutex. Grab the `struct _qsbr_shared` from the interpreter
instead.

files:
M Include/internal/pycore_qsbr.h
M Python/pystate.c
M Python/qsbr.c
M Tools/tsan/suppressions_free_threading.txt

diff --git a/Include/internal/pycore_qsbr.h b/Include/internal/pycore_qsbr.h
index c3680a205542f7..20e643e172b38d 100644
--- a/Include/internal/pycore_qsbr.h
+++ b/Include/internal/pycore_qsbr.h
@@ -140,7 +140,7 @@ _Py_qsbr_register(struct _PyThreadStateImpl *tstate,
 
 // Disassociates a PyThreadState from the QSBR state and frees the QSBR state.
 extern void
-_Py_qsbr_unregister(struct _PyThreadStateImpl *tstate);
+_Py_qsbr_unregister(PyThreadState *tstate);
 
 extern void
 _Py_qsbr_fini(PyInterpreterState *interp);
diff --git a/Python/pystate.c b/Python/pystate.c
index de6a768a50f997..0832b37c278c76 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1794,7 +1794,7 @@ tstate_delete_common(PyThreadState *tstate)
     HEAD_UNLOCK(runtime);
 
 #ifdef Py_GIL_DISABLED
-    _Py_qsbr_unregister((_PyThreadStateImpl *)tstate);
+    _Py_qsbr_unregister(tstate);
 #endif
 
     // XXX Unbind in PyThreadState_Clear(), or earlier
diff --git a/Python/qsbr.c b/Python/qsbr.c
index d7ac8f479cda1b..1e02ff9c2e45f0 100644
--- a/Python/qsbr.c
+++ b/Python/qsbr.c
@@ -231,20 +231,21 @@ _Py_qsbr_register(_PyThreadStateImpl *tstate, 
PyInterpreterState *interp,
 }
 
 void
-_Py_qsbr_unregister(_PyThreadStateImpl *tstate)
+_Py_qsbr_unregister(PyThreadState *tstate)
 {
-    struct _qsbr_shared *shared = tstate->qsbr->shared;
+    struct _qsbr_shared *shared = &tstate->interp->qsbr;
+    struct _PyThreadStateImpl *tstate_imp = (_PyThreadStateImpl*) tstate;
 
     PyMutex_Lock(&shared->mutex);
     // NOTE: we must load (or reload) the thread state's qbsr inside the mutex
     // because the array may have been resized (changing tstate->qsbr) while
     // we waited to acquire the mutex.
-    struct _qsbr_thread_state *qsbr = tstate->qsbr;
+    struct _qsbr_thread_state *qsbr = tstate_imp->qsbr;
 
     assert(qsbr->seq == 0 && "thread state must be detached");
-    assert(qsbr->allocated && qsbr->tstate == (PyThreadState *)tstate);
+    assert(qsbr->allocated && qsbr->tstate == tstate);
 
-    tstate->qsbr = NULL;
+    tstate_imp->qsbr = NULL;
     qsbr->tstate = NULL;
     qsbr->allocated = false;
     qsbr->freelist_next = shared->freelist;
diff --git a/Tools/tsan/suppressions_free_threading.txt 
b/Tools/tsan/suppressions_free_threading.txt
index d5f4cd7acd36b7..dfa4a1fe9ca438 100644
--- a/Tools/tsan/suppressions_free_threading.txt
+++ b/Tools/tsan/suppressions_free_threading.txt
@@ -38,7 +38,6 @@ race_top:_PyParkingLot_Park
 race_top:_PyType_HasFeature
 race_top:assign_version_tag
 race_top:gc_restore_tid
-race_top:initialize_new_array
 race_top:insertdict
 race_top:lookup_tp_dict
 race_top:mi_heap_visit_pages

_______________________________________________
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