gh-115103: Fix unregistering of QSBR state (#116480)

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.
This commit is contained in:
Sam Gross 2024-03-08 12:39:53 -05:00 committed by GitHub
parent 7cee276d55
commit cca30230d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 8 additions and 4 deletions

View File

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