Repository navigation
SEGV in faulthandler.dump_traceback_later #140815
Description
Activity
- addedtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
on Oct 31, 2025 - addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Oct 31, 2025 - changed the title
[-]SEGV in faulthandler[/-][+]SEGV in `faulthandler.dump_traceback_later`[/+]on Oct 31, 2025 Is
this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
relevant? cc @vstinner
I have following repro:
import faulthandler import sys faulthandler.dump_traceback_later(10 * 1e-308, exit=True, file=sys.__stderr__) assert False
It fails with assert in the C code:
Running Debug|x64 interpreter... Traceback (most recent call last): Timeout (0:00:00.000001)! Thread 0x00006e38 (most recent call first): File "X:\Work\cpython\main\Lib\traceback.py" File "X:\Work\cpython\issues\b140815.py", line 8, in <module> assert False ^^^^^ Assertion failed: !PyStackRef_IsNull(f->f_executable), file X:\Work\cpython\main\Include\internal\pycore_interpframe.h, line 21 AssertionErrorIf no one minds, I'd like to take a look.
Reacted by Bénédikt Tran and Mikhail Efimov- addedtriagedThe issue has been accepted as valid by a triager.The issue has been accepted as valid by a triager.
on Oct 31, 2025 This segfault occurs because the
faulthandler_threadruns concurrently with interpreter finalization.This happens because the
timeoutvalue of thedump_traceback_lateris10 * 1e-308which is cropped to 1us. Therefore, thefaulthandler_threadruns as soon as possible.faulthandler_threaddoesn't use any synchronization primitives, so it is not a thread-safe, even in the GIL-enabled build.I found an issue #128400 and a PR #128422 where the call to the
StopTheWorldfunction was added to thefaulthandler_dump_traceback_py_implto prevent multithreading issues in the no-GIL build. Therefore, I believe this approach is valid for this issue as well. For the GIL-enabled build, I added the GIL acquisition.- added 4 commits that reference this issue
on Nov 2, 2025 This segfault occurs because the faulthandler_thread runs concurrently with interpreter finalization.
_Py_DumpTracebackThreads()is called by thefaulthandler.dump_traceback_later()thread while the main thread is freeing its frame._Py_DumpTracebackThreads()reads freed memory and does crash randomly. It already calls_PyMem_IsPtrFreed()in a few places to detect freed memory, but it's not enough.faulthandler_thread doesn't use any synchronization primitives, so it is not a thread-safe, even in the GIL-enabled build.
This is by design.
faulthandler.dump_traceback_later(exit=True)dumps the traceback and exits the process to implement a software watchdog. It is used by buildbots and other CIs to exit after a timeout.faulthandler.dump_traceback_later()should not attempt to acquire the GIL or any other lock since it's used to dump the traceback in case in other deadlocks.Reacted by Sergey MiryanovI wrote #140921 to fix the issue: detect if a frame object or a code object is invalid or freed.
With my fix, I can no longer reproduce the crash: I ran the script in a loop for 1 minute.
Reacted by Sergey Miryanovfaulthandler.dump_traceback_later()should not attempt to acquire the GIL or any other lock since it's used to dump the traceback in case in other deadlocks.Thanks to point me this! It was not clear to me after reading the documentation (it is only one reference to the
deadlockon the page and I just missed it).Dummy example of deadlock:
import faulthandler import threading def work(): lock = threading.Lock() lock.acquire() lock.acquire() lock.release() lock.release() faulthandler.dump_traceback_later(5, exit=True) work() faulthandler.cancel_dump_traceback_later()
Output:
Timeout (0:00:05)! Thread 0x00007fc30261ebc0 [python] (most recent call first): File "/home/vstinner/python/main/x.py", line 7 in work File "/home/vstinner/python/main/x.py", line 12 in <module>faulthandler shows where the deadlock occurs.
Reacted by Mikhail Efimov and Sergey Miryanovfaulthandler shows where the deadlock occurs.
I can use this at work somehow 🤔 ... Thanks!
Reacted by Victor Stinner- added 3 commits that reference this issue
on Nov 4, 2025 Instead of crashing, the initial reproducer now completes with incomplete traceback like:
$ ./python x.py Timeout (0:00:00.000001)! Thread 0x00007f107d86bbc0 [python] (most recent call first): File "/home/vstinner/python/main/Lib/tokenize.py", line ??? in find_cookie <invalid frame>Even if, as I explained in other comments, it's not 100% reliable. I consider that the initial issue has been fixed and I close the issue. Thanks for your bug report.
Reacted by Mikhail Efimov- added a commit that references this issue
on Sep 11, 2026 - added a commit that references this issue
on Sep 24, 2026
Crash report
What happened?
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