-
-
Notifications
You must be signed in to change notification settings - Fork 34.1k
Open
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-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?
After upgrading from 3.13.11 to 3.13.12, we saw a consistent SIGSEGV crash in perf_trampoline from the fork child process when perf support is enabled. Here is a minimal example:
import gc
import os
import sys
def main():
if not sys.is_stack_trampoline_active():
try:
sys.activate_stack_trampoline("perf")
except ValueError:
print("Perf trampoline not supported on this platform")
return
# Execute functions to create trampolined code objects so
# trampoline_refcount > 1 at fork time. Keep references alive.
funcs = []
ns = {}
for i in range(50):
exec(compile(f"def _f{i}(): return {i}", f"<gen-{i}>", "exec"), ns)
f = ns[f"_f{i}"]
f() # Execute to create trampoline
funcs.append(f)
pid = os.fork()
if pid == 0:
# Child: _PyPerfTrampoline_AfterFork_Child has run, leaving two
# active code watchers. We need to create NEW code objects that get
# trampolines at the NEW extra_code_index, so both watchers see
# them and double-decrement trampoline_refcount.
ns2 = {}
for i in range(50):
exec(compile(f"def _g{i}(): return {i}", f"<child-{i}>", "exec"), ns2)
ns2[f"_g{i}"]() # Execute to create trampoline (increments refcount)
# Destroy them — both watchers fire, double-decrement -> SIGSEGV
del ns2
gc.collect()
os._exit(0)
else:
_, status = os.waitpid(pid, 0)
if os.WIFSIGNALED(status):
sig = os.WTERMSIG(status)
print(f"FAIL: Child killed by signal {sig} (SIGSEGV=11)")
sys.exit(1)
else:
exit_code = os.WEXITSTATUS(status)
if exit_code == 0:
print("OK: Child exited normally (bug not triggered)")
else:
print(f"FAIL: Child exited with code {exit_code}")
sys.exit(1)
if __name__ == "__main__":
main()Compiling CPython 3.13.12 with:
./configure CFLAGS="-g -O0" && make -j $(nproc)
Running in gdb shows the crash is here:
❯ PYTHONPERFSUPPORT=1 gdb --args ./python ~/perf_trampoline_crash.py
...
(gdb) set follow-fork-mode child
(gdb) run
...
Thread 2.1 "python" received signal SIGSEGV, Segmentation fault.
[Switching to process 753038]
compile_trampoline () at Python/perf_trampoline.c:411
411 size_t total_code_size = round_up(perf_code_arena->code_size + trampoline_api.code_padding, 16);
After some digging, I believe this is a regression from the bugfix for #143228. Reverting de34f6d makes the crash go away.
This crash is also reproducible at main branch.
CPython versions tested on:
3.13, CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
No response
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump