-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
Crash in ThreadHandle_dealloc
after fork in free-threaded build
#115035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
Comments
This looks reasonable to me. |
colesbury
added a commit
to colesbury/cpython
that referenced
this issue
Feb 5, 2024
This marks dead ThreadHandles as non-joinable earlier in `PyOS_AfterFork_Child()` before we execute any Python code. The handles are stored in a global linked list in `_PyRuntimeState` because `fork()` affects the entire process.
colesbury
added a commit
to colesbury/cpython
that referenced
this issue
Feb 5, 2024
This marks dead ThreadHandles as non-joinable earlier in `PyOS_AfterFork_Child()` before we execute any Python code. The handles are stored in a global linked list in `_PyRuntimeState` because `fork()` affects the entire process.
colesbury
added a commit
that referenced
this issue
Feb 6, 2024
…115042) This marks dead ThreadHandles as non-joinable earlier in `PyOS_AfterFork_Child()` before we execute any Python code. The handles are stored in a global linked list in `_PyRuntimeState` because `fork()` affects the entire process.
fsc-eriker
pushed a commit
to fsc-eriker/cpython
that referenced
this issue
Feb 14, 2024
…king (python#115042) This marks dead ThreadHandles as non-joinable earlier in `PyOS_AfterFork_Child()` before we execute any Python code. The handles are stored in a global linked list in `_PyRuntimeState` because `fork()` affects the entire process.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Bug report
I've seen this in the free-threaded build, but I think the problem can theoretically occur in the default build as well.
The problem is that after a
fork()
, an already deadThreadHandle
may be deallocated before it's marked as not joinable. TheThreadHandle_dealloc()
function can crash inPyThread_detach_thread()
:cpython/Modules/_threadmodule.c
Lines 66 to 70 in bcccf1f
The steps leading to the crash are:
T2
starts and finishes, but is not joined. TheThreadHandle
is not immediately deallocated, either because it's part of a larger reference cycle or due to biased reference counting (in the free-threaded build)fork()
PyOS_AfterFork_Child()
, theThreadHandle
is deallocated. I've seen this happen in the free-threaded build due to biased reference counting merging the thread states inPyThreadState_Clear()
. I believe this can also happen in the default build if, for example, a GC is triggered early on duringthreading._after_fork()
before we get to marking theThreadHandle
as not joinable.Proposed fix
Early on in
PyOS_AfterFork_Child()
, we should fix up allThreadHandle
objects from C (without executing Python code) -- we should mark the dead ones as not joinable and update the remaining active thread.I think it's important to do this without executing Python code. Once we start executing Python code, almost anything can happen, such as GC collections, destructors, etc.
cc @pitrou @gpshead @ericsnowcurrently
Linked PRs
The text was updated successfully, but these errors were encountered: