]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-110481: Fix biased reference counting queue initialization. (#117271)
authorSam Gross <colesbury@gmail.com>
Thu, 28 Mar 2024 13:28:39 +0000 (09:28 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Mar 2024 13:28:39 +0000 (09:28 -0400)
The biased reference counting queue must be initialized from the bound
(active) thread because it uses `_Py_ThreadId()` as the key in a hash
table.

Python/brc.c
Python/pystate.c

index b73c721e71aef6b6ab0139f72981f44f99f61933..8f87bc33007bcf860058e24af6be20b33a88f5b9 100644 (file)
@@ -119,6 +119,8 @@ _Py_brc_merge_refcounts(PyThreadState *tstate)
     struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
     struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
 
+    assert(brc->tid == _Py_ThreadId());
+
     // Append all objects into a local stack. We don't want to hold the lock
     // while calling destructors.
     PyMutex_Lock(&bucket->mutex);
@@ -142,11 +144,12 @@ void
 _Py_brc_init_thread(PyThreadState *tstate)
 {
     struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
-    brc->tid = _Py_ThreadId();
+    uintptr_t tid = _Py_ThreadId();
 
     // Add ourself to the hashtable
-    struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
+    struct _brc_bucket *bucket = get_bucket(tstate->interp, tid);
     PyMutex_Lock(&bucket->mutex);
+    brc->tid = tid;
     llist_insert_tail(&bucket->root, &brc->bucket_node);
     PyMutex_Unlock(&bucket->mutex);
 }
@@ -155,6 +158,13 @@ void
 _Py_brc_remove_thread(PyThreadState *tstate)
 {
     struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
+    if (brc->tid == 0) {
+        // The thread state may have been created, but never bound to a native
+        // thread and therefore never added to the hashtable.
+        assert(tstate->_status.bound == 0);
+        return;
+    }
+
     struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
 
     // We need to fully process any objects to merge before removing ourself
index 921e74ed5a9826bb953cb4d8762795aa6a868755..8489f53c6e3e34d1fff119bc58461a06bb080a6f 100644 (file)
@@ -261,6 +261,12 @@ bind_tstate(PyThreadState *tstate)
     tstate->native_thread_id = PyThread_get_thread_native_id();
 #endif
 
+#ifdef Py_GIL_DISABLED
+    // Initialize biased reference counting inter-thread queue. Note that this
+    // needs to be initialized from the active thread.
+    _Py_brc_init_thread(tstate);
+#endif
+
     // mimalloc state needs to be initialized from the active thread.
     tstate_mimalloc_bind(tstate);
 
@@ -1412,10 +1418,6 @@ init_threadstate(_PyThreadStateImpl *_tstate,
     tstate->what_event = -1;
     tstate->previous_executor = NULL;
 
-#ifdef Py_GIL_DISABLED
-    // Initialize biased reference counting inter-thread queue
-    _Py_brc_init_thread(tstate);
-#endif
     llist_init(&_tstate->mem_free_queue);
 
     if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) {