Skip to content

JIT: assertion failure in _PyObject_GC_UNTRACK #137007

@devdanzin

Description

@devdanzin

Crash report

What happened?

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 two packages in editable mode.

For this special build, apply this diff:

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)
diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h
index 8b7f12bf03d..8cc51959063 100644
--- a/Include/internal/pycore_optimizer.h
+++ b/Include/internal/pycore_optimizer.h
@@ -163,7 +163,7 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst)
 // progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this
 // is the "maximum amount of polymorphism" that an isolated trace tree can
 // handle before rejoining the rest of the program.
-#define MAX_CHAIN_DEPTH 4
+#define MAX_CHAIN_DEPTH 16

 /* Symbols */
 /* See explanation in optimizer_symbols.c */

This MRE must be invoked like this:

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

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

from random import randint

class UnstableHash_unstable_hash_object_v4:
    hash_count = 0

    def __hash__(self):
        self.hash_count += 1
        new_hash = 5 if self.hash_count < 70 else randint(0, 1024)
        print(new_hash)
        return new_hash
unstable_hash_object_v4 = UnstableHash_unstable_hash_object_v4()
tuple_v6 = (90.1433,)

def uop_harness_f1():

    class ShapeA_la_7776:
        payload = 123

    class ShapeB_la_7776:

        @property
        def payload(self):
            return 'property_payload'

    class ShapeC_la_7776:

        def payload(self):
            return id(self)

    class ShapeD_la_7776:
        __slots__ = ['payload']

        def __init__(self):
            self.payload = 'slot_payload'
    shapes_la_7776 = [ShapeA_la_7776(), ShapeB_la_7776(), ShapeC_la_7776(), ShapeD_la_7776()]
    for i in range(500):
        obj = shapes_la_7776[i % len(shapes_la_7776)]
        try:
            payload_val = obj.payload
            if callable(payload_val):
                payload_val()
                payload_val()
                payload_val()
                payload_val()
        except Exception:
            pass
    {unstable_hash_object_v4, unstable_hash_object_v4}
    {unstable_hash_object_v4, unstable_hash_object_v4}
    {unstable_hash_object_v4, unstable_hash_object_v4}
    {unstable_hash_object_v4, unstable_hash_object_v4}
    for i_loop_1589 in {2, 1, 2, 3, 4, 5, 6, 8, 10, 9, 12, 10, 12, 13, 14, 15, 17, 17}:
        x, *y = tuple_v6
    x, *y = tuple_v6
for i_f1 in range(300):
    try:
        uop_harness_f1()
    except Exception as e:
        break

Backtrace:

Python/optimizer.c:269: _PyObject_GC_UNTRACK: Assertion "_PyObject_GC_IS_TRACKED(((PyObject*)(op)))" failed: object not tracked by the garbage collector
Enable tracemalloc to get the memory block allocation traceback

object address  : 0x555555f82230
object refcount : 0
object type     : 0x555555c5e680
object type name: uop_executor
object repr     : <refcnt 0 at 0x555555f82230>

Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized

Current thread 0x00007ffff7ea8780 [python] (most recent call first):
  File "/home/danzin/crashers/jit/reduced_crash_retcode_child_15732_2.py", line 47 in uop_harness_f1
  File "/home/danzin/crashers/jit/reduced_crash_retcode_child_15732_2.py", line 56 in <module>

Program received signal SIGABRT, Aborted.

#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  0x00005555558bba92 in fatal_error_exit (status=<optimized out>) at Python/pylifecycle.c:3155
#6  0x00005555558bd07d in fatal_error (fd=2, header=header@entry=1, prefix=prefix@entry=0x5555559f7e90 <__func__.11> "_PyObject_AssertFailed",
    msg=msg@entry=0x555555980fe5 "_PyObject_AssertFailed", status=status@entry=-1) at Python/pylifecycle.c:3371
#7  0x00005555558bd0ef in _Py_FatalErrorFunc (func=func@entry=0x5555559f7e90 <__func__.11> "_PyObject_AssertFailed",
    msg=msg@entry=0x555555980fe5 "_PyObject_AssertFailed") at Python/pylifecycle.c:3387
#8  0x00005555556dd237 in _PyObject_AssertFailed (obj=obj@entry=0x555555f82230,
    expr=expr@entry=0x5555559a9f60 "_PyObject_GC_IS_TRACKED(((PyObject*)(op)))",
    msg=msg@entry=0x5555559a9f30 "object not tracked by the garbage collector", file=file@entry=0x55555598c050 "Python/optimizer.c",
    line=line@entry=269, function=function@entry=0x555555a9c010 <__func__.9> "_PyObject_GC_UNTRACK") at Objects/object.c:3165
#9  0x00005555558a2303 in _PyObject_GC_UNTRACK (filename=filename@entry=0x55555598c050 "Python/optimizer.c", lineno=lineno@entry=269,
    op=op@entry=0x555555f82230) at ./Include/internal/pycore_gc.h:269
#10 0x00005555558a3198 in uop_dealloc (op=op@entry=0x555555f82230) at Python/optimizer.c:269
#11 0x00005555556dc978 in _Py_Dealloc (op=op@entry=0x555555f82230) at Objects/object.c:3206
#12 0x00005555557b47ab in Py_DECREF_MORTAL (filename=filename@entry=0x5555559aaec8 "./Include/internal/pycore_stackref.h", lineno=lineno@entry=701,
    op=0x555555f82230) at ./Include/internal/pycore_object.h:450
#13 0x00005555557b485b in PyStackRef_CLOSE (ref=..., ref@entry=...) at ./Include/internal/pycore_stackref.h:701
#14 0x00005555557cfe33 in _PyEval_EvalFrameDefault (tstate=0x555555cca298 <_PyRuntime+331064>, frame=0x7fffffffce30, throwflag=0)
    at Python/generated_cases.c.h:7656
#15 0x00005555557dd559 in _PyEval_EvalFrame (tstate=tstate@entry=0x555555cca298 <_PyRuntime+331064>, frame=frame@entry=0x7ffff7fac180,
    throwflag=throwflag@entry=0) at ./Include/internal/pycore_ceval.h:119
#16 0x00005555557dd72a in _PyEval_Vector (tstate=0x555555cca298 <_PyRuntime+331064>, func=0x7ffff74e8650, locals=locals@entry=0x0,
    args=0x7fffffffd008, argcount=<optimized out>, kwnames=0x0) at Python/ceval.c:1977
#17 0x000055555567dc31 in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>)
    at Objects/call.c:413
#18 0x000055555567df88 in _PyObject_VectorcallTstate (tstate=0x555555cca298 <_PyRuntime+331064>, callable=callable@entry=0x7ffff74e8650,
    args=args@entry=0x7fffffffd008, nargsf=nargsf@entry=9223372036854775809, kwnames=kwnames@entry=0x0) at ./Include/internal/pycore_call.h:169
#19 0x000055555567e0b4 in PyObject_CallOneArg (func=func@entry=0x7ffff74e8650, arg=arg@entry=0x7ffff728c8a0) at Objects/call.c:395
#20 0x000055555570a05e in call_unbound_noarg (unbound=unbound@entry=1, func=func@entry=0x7ffff74e8650, self=self@entry=0x7ffff728c8a0)
    at Objects/typeobject.c:3019
#21 0x000055555571717f in maybe_call_special_no_args (self=self@entry=0x7ffff728c8a0, attr=<optimized out>,
    attr_is_none=attr_is_none@entry=0x7fffffffd084) at Objects/typeobject.c:3132
#22 0x000055555571746b in slot_tp_hash (self=0x7ffff728c8a0) at Objects/typeobject.c:10489
#23 0x00005555556dbf44 in PyObject_Hash (v=0x7ffff728c8a0) at Objects/object.c:1158
#24 0x00005555556fb0b2 in _PyObject_HashFast (op=op@entry=0x7ffff728c8a0) at ./Include/internal/pycore_object.h:872
#25 0x00005555556ffaaf in _PySet_AddTakeRef (so=0x7ffff72e5c70, key=0x7ffff728c8a0) at Objects/setobject.c:234
#26 0x00007ffff706a948 in ?? ()
#27 0xfffffffffffffffe in ?? ()
#28 0x0000555555cca298 in _PyRuntime ()
#29 0x00007fffffffd420 in ?? ()
#30 0x00007ffff70a9017 in ?? ()
#31 0x0000555555eb4dc0 in ?? ()
#32 0x00007ffff70a9000 in ?? ()
#33 0x0000555555cca298 in _PyRuntime ()
#34 0x00007ffff7fac0a0 in ?? ()
#35 0x00007ffff7fac160 in ?? ()
#36 0x00005555557ca1c0 in _PyEval_EvalFrameDefault (tstate=<error reading variable: Cannot access memory at address 0xfffffffffffffda0>,
    frame=0xffffffffffffffff, throwflag=<error reading variable: Cannot access memory at address 0xfffffffffffffd8c>)
    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_debug_15732.txt
lltrace_15732.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 22 2025, 11:26:33) [GCC 14.2.0]

Linked PRs

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

    pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy