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.