Skip to content

JIT: executor->vm_data.valid assertion failure in unlink_executor #136996

@devdanzin

Description

@devdanzin

Crash report

What happened?

Sorry about the messy and convoluted bug report, I hope something interesting might be gleaned from it.

It's possible to non-deterministically abort a special debug JIT build by running the code below, running from a Python executable from a venv where you installed a package in editable mode. This darn requirement for an install in editable mode stumped me for hours!

For this special build, apply this diff (couldn't get it to work in a normal build by changing loop lengths):

index 454c8dde031..9e21c41421a 100644
--- a/Include/internal/pycore_backoff.h
+++ b/Include/internal/pycore_backoff.h
@@ -99,8 +99,8 @@ backoff_counter_triggers(_Py_BackoffCounter counter)
 // Must be larger than ADAPTIVE_COOLDOWN_VALUE, otherwise when JIT code is
 // invalidated we may construct a new trace before the bytecode has properly
 // re-specialized:
-#define JUMP_BACKWARD_INITIAL_VALUE 4095
-#define JUMP_BACKWARD_INITIAL_BACKOFF 12
+#define JUMP_BACKWARD_INITIAL_VALUE 63
+#define JUMP_BACKWARD_INITIAL_BACKOFF 6
 static inline _Py_BackoffCounter
 initial_jump_backoff_counter(void)
 {
@@ -112,8 +112,8 @@ initial_jump_backoff_counter(void)
  * Must be larger than ADAPTIVE_COOLDOWN_VALUE,
  * otherwise when a side exit warms up we may construct
  * a new trace before the Tier 1 code has properly re-specialized. */
-#define SIDE_EXIT_INITIAL_VALUE 4095
-#define SIDE_EXIT_INITIAL_BACKOFF 12
+#define SIDE_EXIT_INITIAL_VALUE 63
+#define SIDE_EXIT_INITIAL_BACKOFF 6

 static inline _Py_BackoffCounter
 initial_temperature_backoff_counter(void)

This MRE must be invoked like this:

/path/to/venv/with/editable/install/bin/python mre.py

Sorry about the long MRE, this code seems stubbornly hard to reduce. MRE:

from random import random

class C_object_v1:

    def __getitem__(self, item):
        return 5
object_v1 = C_object_v1()


int_v4 = -51452741571812374
float_v6 = 46.1
float_v7 = 77.26

class StatefulLen_stateful_len_object_v12:
    def __init__(self):
        self.len_count = 0

    def __len__(self):
        _len = 0 if self.len_count < 70 else 99
        self.len_count += 1
        return _len
stateful_len_object_v12 = StatefulLen_stateful_len_object_v12()

def uop_harness_f1():
    class StatefulIter_uop_harness_f1_6059:

        def __init__(self):
            self._iter_count = 0
            self._iterable = {1, 2, 3}

        def __iter__(self):
            self._iter_count += 1
            if self._iter_count <= 67:
                return iter((None,))
            return iter(self._iterable)
    uop_harness_f1_6059 = StatefulIter_uop_harness_f1_6059()
    evil_iterable = StatefulIter_uop_harness_f1_6059()
    for _ in range(100):
        tuple(evil_iterable)
    object_v1 = globals()['object_v1']

    class SwappedClass_2950:
        pass
    object_v1.__class__ = SwappedClass_2950
    if object_v1:
        pass
    for i_loop_9595 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] * 50:
        res_compareopint = int_v4 > int_v4
    if random() < 0.01:
        object_v1.__class__.get_value = lambda *a, **kw: 'patched!'
for i_f1 in range(500):
    try:
        uop_harness_f1()
    except Exception:
        break

Backtrace:

python: Python/optimizer.c:1436: unlink_executor: Assertion `executor->vm_data.valid' failed.

Program received signal SIGABRT, Aborted.
Download failed: Invalid argument.  Continuing without source file ./nptl/./nptl/pthread_kill.c.
__pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0)
    at ./nptl/pthread_kill.c:44
warning: 44     ./nptl/pthread_kill.c: No such file or directory
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0)
    at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6)
    at ./nptl/pthread_kill.c:100
#3  0x00007ffff7c4579e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff7c288cd in __GI_abort () at ./stdlib/abort.c:73
#5  0x00007ffff7c28830 in __assert_fail_base (fmt=<optimized out>, assertion=<optimized out>,
    file=<optimized out>, line=<optimized out>, function=<optimized out>) at ./assert/assert.c:118
#6  0x00007ffff7c3be1f in __assert_fail (assertion=<optimized out>, file=<optimized out>,
    line=<optimized out>, function=<optimized out>) at ./assert/assert.c:127
#7  0x00005555558a2603 in unlink_executor (executor=executor@entry=0x555555f44480)
    at Python/optimizer.c:1436
#8  0x00005555558a31a7 in uop_dealloc (op=op@entry=0x555555f44480) at Python/optimizer.c:271
#9  0x00005555556dc978 in _Py_Dealloc (op=0x555555f44480) at Objects/object.c:3206
#10 0x00007ffff71d59f7 in ?? ()
#11 0x00007fffffffd470 in ?? ()
#12 0x00007ffff71d522b in ?? ()
#13 0x00007fffffffd470 in ?? ()
#14 0x00007ffff71d4017 in ?? ()
#15 0x0000555555e60c70 in ?? ()
#16 0x00007ffff71d4000 in ?? ()
#17 0x0000555555cca298 in _PyRuntime ()
#18 0x00007ffff7fac0b8 in ?? ()
#19 0x00007ffff7fac160 in ?? ()
#20 0x00005555557ca1c0 in _PyEval_EvalFrameDefault (tstate=0xcdcdcdcdcdcdcdcd, frame=0x555555cca298 <_PyRuntime+331064>, throwflag=-842150451)
    at Python/generated_cases.c.h:5598
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Here are the outputs from running with PYTHON_OPT_DEBUG=4 and PYTHON_LLTRACE=4, since they are too long I've attached them as files:
opt_debug2.txt
lltrace2.txt

Found using lafleur.

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:6bf1c0ab349, Jul 21 2025, 20:28:08) [GCC 14.2.0]

Metadata

Metadata

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)topic-JITtype-crashA hard crash of the interpreter, possibly with a core dump

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions