From fa67e46142dd76842b499fd3fb711c40f7dfdc7d Mon Sep 17 00:00:00 2001 From: Vamsi-klu Date: Sun, 26 Jul 2026 07:10:54 +0000 Subject: [PATCH] gh-153852: Assert thread list non-empty only after stopping the world Move the threads.head assert in handle_thread_shutdown_exception to after _PyEval_StopTheWorld so it does not race tstate_delete_common (TSAN-0034). --- .../2026-07-26-12-00-00.gh-issue-153852.a1b2c3.rst | 1 + Python/pylifecycle.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-12-00-00.gh-issue-153852.a1b2c3.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-12-00-00.gh-issue-153852.a1b2c3.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-12-00-00.gh-issue-153852.a1b2c3.rst new file mode 100644 index 000000000000000..7eae5d343cf213a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-12-00-00.gh-issue-153852.a1b2c3.rst @@ -0,0 +1 @@ +Fix a free-threading race in finalization by asserting the thread list is non-empty only after stopping the world. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 01ca459b2eb2b8f..7ebde15b6b7e259 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3827,8 +3827,8 @@ handle_thread_shutdown_exception(PyThreadState *tstate) assert(tstate != NULL); assert(_PyErr_Occurred(tstate)); PyInterpreterState *interp = tstate->interp; - assert(interp->threads.head != NULL); _PyEval_StopTheWorld(interp); + assert(interp->threads.head != NULL); /* safe: world is stopped */ // We don't have to worry about locking this because the // world is stopped.