Repository navigation
Main segfaults importing _pyrepl with low value for JUMP_BACKWARD_INITIAL_VALUE #137218
Description
Crash report
What happened?
Edit: I'm seeing this crash even without patching JUMP_BACKWARD_INITIAL_VALUE. Will try to figure out a MRE for unpatched crash.
If we #define JUMP_BACKWARD_INITIAL_VALUE 702 (or lower) in Include/internal/pycore_backoff.h, a debug JIT build will segfault when trying to run to the new REPL. Can also be triggered by:
python -m _pyrepl
Using some other modules like random or http.server doesn't crash.
An even lower value like 344 will segfault earlier, during the build process.
This happens since #136307 landed in 377b787.
The diff below, which is part of that commit, is enough to cause the segfault together with defining JUMP_BACKWARD_INITIAL_VALUE to 702 or lower:
diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h
index 493377b4c25..5e7dda3a371 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -1005,6 +1005,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(imag));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(in_fd));
+ _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(include_aliases));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(incoming));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(index));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(indexgroup));
diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h
index 5dfea2f479d..6908cbf78f3 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -496,6 +496,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(imag)
STRUCT_FOR_ID(importlib)
STRUCT_FOR_ID(in_fd)
+ STRUCT_FOR_ID(include_aliases)
STRUCT_FOR_ID(incoming)
STRUCT_FOR_ID(index)
STRUCT_FOR_ID(indexgroup)
diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h
index 85ced09d29d..da2ed7422c9 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -1003,6 +1003,7 @@ extern "C" {
INIT_ID(imag), \
INIT_ID(importlib), \
INIT_ID(in_fd), \
+ INIT_ID(include_aliases), \
INIT_ID(incoming), \
INIT_ID(index), \
INIT_ID(indexgroup), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h
index 6018d98d156..b1f411945e7 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -1772,6 +1772,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
+ string = &_Py_ID(include_aliases);
+ _PyUnicode_InternStatic(interp, &string);
+ assert(_PyUnicode_CheckConsistency(string, 1));
+ assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(incoming);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));Backtrace:
Program received signal SIGSEGV, Segmentation fault.
_PyUnicode_Equal (str1=0x555555c88c18 <_PyRuntime+96088>, str2=0x555555c88c50 <_PyRuntime+96144>) at ./Include/object.h:815
815 return ((flags & feature) != 0);
#0 _PyUnicode_Equal (str1=0x555555c88c18 <_PyRuntime+96088>, str2=0x555555c88c50 <_PyRuntime+96144>) at ./Include/object.h:815
#1 0x00007ffff731df15 in ?? ()
#2 0x00007ffff764a751 in ?? ()
#3 0x0000555555cc2230 in _PyRuntime ()
#4 0x00007fffffffbfc0 in ?? ()
#5 0x00007ffff7317017 in ?? ()
#6 0x0000555556053f60 in ?? ()
#7 0x00007ffff7e2a9c8 in ?? ()
#8 0x00007ffff7317000 in ?? ()
#9 0x00007ffff7e2a910 in ?? ()
#10 0x0000555555cc2230 in _PyRuntime ()
#11 0x00005555557cdcf9 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=0x58, throwflag=1291845632)
at Python/generated_cases.c.h:7796
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
Here's the output from running PYTHON_LLTRACE=4 ./python -m _pyrepl:
lltrace_crash.txt
And here for PYTHON_OPT_DEBUG=4 ./python -m _pyrepl:
opt_debug_crash.txt
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a0 (heads/main-dirty:d7e12a362a2, Jul 29 2025, 18:24:07) [GCC 13.3.0]
Activity
brandtbucher commentedon Jul 29, 2025
This is only on JIT builds, correct? Curious to see the new unpatched reproducer.
devdanzin commentedon Jul 29, 2025
AFAICT, after double checking, yes.
brandtbucher commentedon Jul 29, 2025
I suspect that the bug isn't the initial value itself, but rather the code we try to compile when the value is that low. It could be that some specialization or inline cache has a nonsense value that we're not handling well, or something.
brandtbucher commentedon Jul 29, 2025
Is part of this file missing, or was the output truncated by the crash itself? The last optimized trace is incomplete (it should be length 167, but only 132 elements are printed).
Or maybe we need to add a
flushcall somewhere?devdanzin commentedon Jul 29, 2025
I believe the crash truncates it, yes.
devdanzin commentedon Jul 30, 2025
I'm suspicious about such straightforward code segfaulting, hoping this isn't an operator error on my part.
Here's something that triggers the right crash for me, unpatched debug JIT build, please confirm whether it repros:
And here's something that triggers another crash, not sure what configurations are affected (will investigate tomorrow), but also crashes an unpatched debug JIT build:
Traceback for 2nd crash:
Here's the output from running with
PYTHON_LLTRACE=4for the second crash:lltrace_2nd_crash.txt
And here's the output from
PYTHON_OPT_DEBUG=4:opt_debug_2nd_crash.txt
brandtbucher commentedon Jul 30, 2025
Yep! This gives me a segfault:
This gives me an assertion failure (
_POP_TOP_UNICODE.c:121: _Py_CODEUNIT *_JIT_ENTRY(_PyInterpreterFrame *, _PyStackRef *, PyThreadState *): Assertion `PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))' failed.):Your second reproducer looks a lot like my second one here, and I wouldn't be surprised if both of these are related. Something about string indexing is broken.
brandtbucher commentedon Jul 30, 2025
Hm, weird. After a
make cleanand rebuild the issue goes away.brandtbucher commentedon Jul 30, 2025
Maybe our
makerule for the JIT is broken. I think we need to say thatjit.odepends onjit_stencils*.h, not justjit_stencils.h. We now have a platform-specific header file (likejit_stencils-x86_64-pc-linux-gnu.h) and I'm not sure that the existing logic is picking that dependency up correctly.@devdanzin, does a clean rebuild work correctly for you?
devdanzin commentedon Jul 30, 2025
Great, I was really worried it was my fault 😄
It still segfaults after make distclean, but if I also bypass ccache it stops crashing. Then patching and re-enabling ccache also doesn't crash, which makes no sense to me but I hope makes to you.
Edit: I simply can't repro anymore, any idea about how to bring the brokenness back?
Edit 2: BTW, I see
make distcleandoesrm -f jit_stencils.h, should it also removejit_stencils*.h?brandtbucher commentedon Jul 30, 2025
So I'm comfortable calling this a bug in the build system, not in the JIT. Are you interested in fixing it? You can ping me for help/review. Should be a couple of fairly straightforward changes in the Makefile.
CC @savannahostrowski since she might have thoughts here.
devdanzin commentedon Jul 30, 2025
I'd rather not tackle this one, but thanks for asking.
Are you able to get back into the broken state? I wasted too much time trying to yesterday 😅.
brandtbucher commentedon Jul 30, 2025
I think getting into the broken state is hard for the same reasons that getting out of the broken state is hard. ;)
GH-137218: Update `make` for JIT stencils (#137265)
GH-137218: Fix Makefile to handle FreeBSD (fix for JIT stencil change…
encukou commentedon Sep 22, 2025
Since the PR was merged, running
maketwice (on the same source) will compilePrograms/_freeze_moduleagain and re-freeze a bunch of modules. Would it be possible to avoid that?savannahostrowski commentedon Sep 22, 2025
Hmm, let me investigate this a bit.
encukou commentedon Sep 22, 2025
Thanks!
If you want me to look into it, just shout :)
GH-137218: Fix unnecessary recompile of `Programs/_freeze_module` (#1…
pythonGH-137218: Fix unnecessary recompile of `Programs/_freeze_modul…