Repository navigation
Subinterpreters don't properly clean up threads #128639
Copy link
Copy link
Closed
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-subinterpreterstype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
Crash report
What happened?
I found this issue a little while back, but I'm finally getting around to fixing it.
Currently, subinterpreter finalization assumes that there's only one thread left. So, any remaining threads--daemon or non-daemon--crash the interpreter upon finalizing:
import _interpreters
interp = _interpreters.create()
source = """
import threading
import time
def hello():
time.sleep(1)
t = threading.Thread(target=hello)
t.start()
"""
_interpreters.run_string(interp, source)This results in an assertion failure on my end:
python: Python/pystate.c:1969: tstate_activate: Assertion `!tstate->_status.bound_gilstate || tstate == gilstate_tss_get((tstate->interp->runtime))' failed.
So, there's a few things that need to get fixed:
- The finalization process shouldn't assume that there's one thread. Instead, it should just dive straight into
Py_EndInterpreter, which will properly clean things up. - It also shouldn't try to manually delete threads via attaching to them and then calling
PyThreadState_Delete. That should also happen inPy_EndInterpreter, after all threads have finished. - Subinterpreter finalization itself happens way too late.
_PyRuntimeState_SetFinalizinghas been set, meaning that all threads will be already blocked, and thus cannot shutdown viathreading._shutdown, resulting in a deadlock.finalize_subinterpretersshould be called before that happens.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
No response
Linked PRs
- gh-128639: Don't assume one thread in subinterpreter finalization #128640
- [3.14] gh-128639: Don't assume one thread in subinterpreter finalization (gh-128640) #134254
- Revert "gh-128639: Don't assume one thread in subinterpreter finalization (gh-128640)" #134256
- gh-128639: Don't assume one thread in subinterpreter finalization with fixed daemon thread support #134606
- [3.14] gh-128639: Don't assume one thread in subinterpreter finalization with fixed daemon thread support (GH-134606) #139050
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-subinterpreterstype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Projects
- StatusShow more project fieldsDone
Activity
ericsnowcurrently commentedon May 19, 2025
FWIW, I thought I had created an issue about cleaning up lingering thread states automatically. Would you mind double-checking and closing it, if so?
gh-128639: Don't assume one thread in subinterpreter finalization (gh…
pythongh-128639: Don't assume one thread in subinterpreter finalizati…
Revert "pythongh-128639: Don't assume one thread in subinterpreter fi…
Revert "gh-128639: Don't assume one thread in subinterpreter finaliza…
ZeroIntensity commentedon May 21, 2025
For those who aren't me or Eric: we had to revert the fix because it breaks the test suite when run with
--single-process. I'm still trying to figure out why.ZeroIntensity commentedon May 24, 2025
@ericsnowcurrently I finally figured out the buildbot failures. This is an awesome bug.
Here's a repro that crashes with my patch applied:
The problem is that something subtly changed with daemon thread shutdown in-between writing my patch and merging it. So, after the
time.sleep()call, the thread would still be alive and crash. Unfortunately for me, I randomly chose 100 seconds as the sleep time, so if the process exited within those 100 seconds, nothing would crash. I'll put up the fixed version.Reapply "pythongh-128639: Don't assume one thread in subinterpreter f…
sergey-miryanov commentedon Jul 8, 2025
I have a following repro:
I tested it on main and on #134606 (with merged main). func with
assert Falsecrashes with following stack trace:ZeroIntensity commentedon Jul 8, 2025
No idea yet. Let's wait until we get thread cleanup fixed and then we can investigate that one in a new issue.
pythongh-128639: Don't assume one thread in subinterpreter finalizati…
Revert "pythongh-128639: Don't assume one thread in subinterpreter fi…
pythongh-128639: Don't assume one thread in subinterpreter finalizati…
Revert "pythongh-128639: Don't assume one thread in subinterpreter fi…
gh-128639: Don't assume one thread in subinterpreter finalization wit…
pythongh-128639: Don't assume one thread in subinterpreter finalizati…
[3.14] gh-128639: Don't assume one thread in subinterpreter finalizat…
sergey-miryanov commentedon Nov 4, 2025
FTR, repro from #128639 (comment) seems to have been fixed. It produces:
Thanks!