From 93e51c9b779e6f2ff914beff49f0b9d203b6b519 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 15 Oct 2024 12:09:35 -0400 Subject: [PATCH] gh-124375: Avoid calling `_PyMem_ProcessDelayed` on other thread states (GH-124459) This fixes a crash when running the PyO3 test suite on the free-threaded build. The `qsbr` field is initialized after the `PyThreadState` is added to the interpreter's linked list -- it might still be NULL. Instead, we "steal" the queue of to-be-freed memory blocks. This is always initialized (possibly empty) and protected by the stop the world pause. (cherry picked from commit 54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933) Co-authored-by: Sam Gross --- ...4-10-15-15-29-41.gh-issue-124375.wNrWVa.rst | 1 + Python/gc_free_threading.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst new file mode 100644 index 00000000000000..4bd17a6e683bc7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst @@ -0,0 +1 @@ +Fix a crash in the free threading build when the GC runs concurrently with a new thread starting. diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 140f1eaa88bfc2..1d8641b91da662 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -340,18 +340,24 @@ merge_all_queued_objects(PyInterpreterState *interp, struct collection_state *st static void process_delayed_frees(PyInterpreterState *interp) { - // In STW status, we can observe the latest write sequence by - // advancing the write sequence immediately. + // While we are in a "stop the world" pause, we can observe the latest + // write sequence by advancing the write sequence immediately. _Py_qsbr_advance(&interp->qsbr); _PyThreadStateImpl *current_tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); _Py_qsbr_quiescent_state(current_tstate->qsbr); + + // Merge the queues from other threads into our own queue so that we can + // process all of the pending delayed free requests at once. HEAD_LOCK(&_PyRuntime); - PyThreadState *tstate = interp->threads.head; - while (tstate != NULL) { - _PyMem_ProcessDelayed(tstate); - tstate = (PyThreadState *)tstate->next; + for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) { + _PyThreadStateImpl *other = (_PyThreadStateImpl *)p; + if (other != current_tstate) { + llist_concat(¤t_tstate->mem_free_queue, &other->mem_free_queue); + } } HEAD_UNLOCK(&_PyRuntime); + + _PyMem_ProcessDelayed((PyThreadState *)current_tstate); } // Subtract an incoming reference from the computed "gc_refs" refcount. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy