]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117657: Fix QSBR race condition (#118843)
authorAlex Turner <alexturner@meta.com>
Fri, 10 May 2024 14:26:35 +0000 (15:26 +0100)
committerGitHub <noreply@github.com>
Fri, 10 May 2024 14:26:35 +0000 (10:26 -0400)
`_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.

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

index c3680a205542f77d33bf083b03ff855e4a630273..20e643e172b38d7f38009323efefb35b6d756730 100644 (file)
@@ -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);
index de6a768a50f99748aaf4adcdc53768ce0f4e1839..0832b37c278c7667f1489a24326086265d7bda58 100644 (file)
@@ -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
index d7ac8f479cda1ba0352068bff7d2a17a671f4e64..1e02ff9c2e45f0e78f8253027348844cafb902d7 100644 (file)
@@ -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;
index d5f4cd7acd36b7fe304e2cd4b3dff14437cd7242..dfa4a1fe9ca43819e978b1e9afdb4038fb4aa34f 100644 (file)
@@ -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