]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-115103: Fix unregistering of QSBR state (#116480)
authorSam Gross <colesbury@gmail.com>
Fri, 8 Mar 2024 17:39:53 +0000 (12:39 -0500)
committerGitHub <noreply@github.com>
Fri, 8 Mar 2024 17:39:53 +0000 (12:39 -0500)
If a thread blocks while waiting on the `shared->mutex` lock, the array
of QSBR states may be reallocated. The `tstate->qsbr` values before the
lock is acquired may not be the same as the value after the lock is acquired.

Python/qsbr.c

index 69f77f490828192e701b3ea2fa805659bb48c662..d7ac8f479cda1ba0352068bff7d2a17a671f4e64 100644 (file)
@@ -233,13 +233,17 @@ _Py_qsbr_register(_PyThreadStateImpl *tstate, PyInterpreterState *interp,
 void
 _Py_qsbr_unregister(_PyThreadStateImpl *tstate)
 {
+    struct _qsbr_shared *shared = tstate->qsbr->shared;
+
+    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_shared *shared = qsbr->shared;
 
     assert(qsbr->seq == 0 && "thread state must be detached");
-
-    PyMutex_Lock(&shared->mutex);
     assert(qsbr->allocated && qsbr->tstate == (PyThreadState *)tstate);
+
     tstate->qsbr = NULL;
     qsbr->tstate = NULL;
     qsbr->allocated = false;