GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — JIT: assertion failure in _PyObject_GC_UNTRACK · Issue #137007 · python/cpython

JIT: assertion failure in _PyObject_GC_UNTRACK #137007

New issue
Copy link
New issue
Copy link
Closed
Closed
JIT: assertion failure in _PyObject_GC_UNTRACK#137007
Copy link
Assignees
Fidget-Spinner
Labels
3.14bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-JITtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump

Description

@devdanzin
devdanzin
opened on Jul 22, 2025
Issue body actions

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

  • gh-137007: Track executor before any possible deallocations #137016
  • [3.14] gh-137007: Track executor before any possible deallocations (GH-137016) #142541

Activity

  1. devdanzin
    added
    type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    on Jul 22, 2025
  2. StanFromIreland
    added
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    topic-JIT
    on Jul 22, 2025
  3. Fidget-Spinner commented on Jul 22, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Jul 22, 2025
    Member
    More actions

    I cannot seem to reproduce this with a debug build of the JIT and with a patch applied, for the reproducer. The reproducer runs till completion for me.

  4. Fidget-Spinner
    self-assigned this
    on Jul 22, 2025
  5. Fidget-Spinner commented on Jul 22, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Jul 22, 2025
    Member
    More actions

    Wait sorry, I didn't see that you need two packages in editable mode for this. Re-investigating.

  6. brandtbucher commented on Jul 22, 2025

    @brandtbucher
    brandtbucher
    on Jul 22, 2025
    Member
    More actions

    I feel like that part is probably a red herring. Probably the import machinery is taking a different path to find random when that's the case, causing GC to happen or something.

  7. Fidget-Spinner commented on Jul 22, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Jul 22, 2025
    Member
    More actions

    I feel like that part is probably a red herring. Probably the import machinery is taking a different path to find random when that's the case, causing GC to happen or something.

    I tried tweaking GC thresholds and don't get anything either. It's not a GC problem. I narrowed it down to the code path in the executor code deallocating the executor when it's not yet tracked by GC.

  8. devdanzin commented on Jul 22, 2025

    @devdanzin
    devdanzin
    on Jul 22, 2025
    MemberAuthor
    More actions

    I was able to reproduce this by (cloning, then) installing pip and pypa/sampleproject as editable. However, it somehow led to a segfault this time:

    Program received signal SIGSEGV, Segmentation fault.
    _PyObject_GC_UNTRACK (op=0x555555e448a0) at ./Include/internal/pycore_gc.h:279
    279         _PyGCHead_SET_NEXT(prev, next);
    
    #0  _PyObject_GC_UNTRACK (op=0x555555e448a0) at ./Include/internal/pycore_gc.h:279
    #1  uop_dealloc (op=0x555555e448a0) at Python/optimizer.c:269
    #2  0x00005555556c059d in _Py_Dealloc (op=0x555555e448a0) at Objects/object.c:3206
    #3  0x00005555557c86de in Py_DECREF_MORTAL (op=<optimized out>) at ./Include/internal/pycore_object.h:482
    #4  PyStackRef_CLOSE (ref=...) at ./Include/internal/pycore_stackref.h:701
    #5  _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>) at Python/generated_cases.c.h:7656
    #6  0x00005555557d2b3c in _PyEval_EvalFrame (tstate=0x555555bb9a48 <_PyRuntime+315048>, frame=<optimized out>, throwflag=0)
        at ./Include/internal/pycore_ceval.h:119
    #7  _PyEval_Vector (tstate=0x555555bb9a48 <_PyRuntime+315048>, func=0x7ffff7496fb0, locals=0x0, args=0x7fffffffd178, argcount=<optimized out>,
        kwnames=<optimized out>) at Python/ceval.c:1977
    #8  0x000055555564905b in _PyObject_VectorcallTstate (tstate=0x555555bb9a48 <_PyRuntime+315048>, callable=0x7ffff7496fb0, args=0x7fffffffd178,
        nargsf=9223372036854775809, kwnames=0x0) at ./Include/internal/pycore_call.h:169
    #9  PyObject_CallOneArg (func=func@entry=0x7ffff7496fb0, arg=arg@entry=0x7ffff7333b60) at Objects/call.c:395
    #10 0x00005555556feed2 in call_unbound_noarg (unbound=<optimized out>, func=0x7ffff7496fb0, self=0x7ffff7333b60) at Objects/typeobject.c:3019
    #11 maybe_call_special_no_args (self=0x7ffff7333b60, attr=<optimized out>, attr_is_none=<synthetic pointer>) at Objects/typeobject.c:3132
    #12 slot_tp_hash (self=0x7ffff7333b60) at Objects/typeobject.c:10489
    #13 0x00005555556e8e95 in _PyObject_HashFast (op=0x7ffff7333b60) at ./Include/internal/pycore_object.h:872
    #14 _PySet_AddTakeRef (so=0x7ffff73bd2a0, key=0x7ffff7333b60) at Objects/setobject.c:234
    #15 0x00007ffff71c0225 in ?? ()
    #16 0x00007fffffffd590 in ?? ()
    #17 0xfffffffffffffffe in ?? ()
    #18 0x00007fffffffd590 in ?? ()
    #19 0x00007ffff71c7017 in ?? ()
    #20 0x00007ffff7fac0a0 in ?? ()
    #21 0x00007ffff7fac160 in ?? ()
    #22 0x0000555555c720c0 in ?? ()
    #23 0x0000555555b70319 in _PyRuntime ()
    #24 0x0000555555d11116 in ?? ()
    #25 0x00005555557ca888 in _PyEval_EvalFrameDefault (tstate=<error reading variable: Cannot access memory at address 0xfffffffffffffd58>,
        frame=<optimized out>, throwflag=<optimized out>) at Python/generated_cases.c.h:5598
    Backtrace stopped: previous frame inner to this frame (corrupt stack?)
    

    Can you reproduce by installing those two packages?

  9. devdanzin commented on Jul 22, 2025

    @devdanzin
    devdanzin
    on Jul 22, 2025
    MemberAuthor
    More actions

    Here's a reproducer for the segfault in a JIT non-debug build without the need of installing packages, please use 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..fee929f122f 100644
    --- a/Include/internal/pycore_optimizer.h
    +++ b/Include/internal/pycore_optimizer.h
    @@ -121,7 +121,7 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp);
     // This is the length of the trace we project initially.
     #define UOP_MAX_TRACE_LENGTH 800
    
    -#define TRACE_STACK_SIZE 5
    +#define TRACE_STACK_SIZE 10
    
     int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame,
         _PyUOpInstruction *trace, int trace_len, int curr_stackentries,
    @@ -152,7 +152,7 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst)
     }
    
     // Holds locals, stack, locals, stack ... co_consts (in that order)
    -#define MAX_ABSTRACT_INTERP_SIZE 4096
    +#define MAX_ABSTRACT_INTERP_SIZE 8192
    
     #define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5)
    
    @@ -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 */

    And this reproducer:

    import sys
    from importlib.machinery import all_suffixes as module_suffixes  # Not sure why, but this unused import seems necessary
    from importlib.util import spec_from_file_location
    
    class _EditableFinder:
        @classmethod
        def _find_spec(cls, fullname, candidate_path):
            return spec_from_file_location(fullname, candidate_path.with_suffix("pyc"))
    
    class _EditableFinder2:
        @classmethod
        def _find_spec(cls, fullname, candidate_path):
            return spec_from_file_location(fullname, candidate_path.with_suffix("py"))
    
    sys.meta_path.append(_EditableFinder)
    sys.meta_path.append(_EditableFinder2)
    
    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
  10. brandtbucher commented on Jul 22, 2025

    @brandtbucher
    brandtbucher
    on Jul 22, 2025
    Member
    More actions

    Here's a reproducer for the segfault in a JIT non-debug build without the need of installing packages, please use this diff:

    Hm, this isn't working for me. Non-debug build, patches applied, no venv.

  11. devdanzin commented on Jul 22, 2025

    @devdanzin
    devdanzin
    on Jul 22, 2025
    MemberAuthor
    More actions

    Hm, this isn't working for me. Non-debug build, patches applied, no venv.

    This isn't my make-it-reliably-reproducible day, is it? It doesn't work without a venv for me either, and it turns out I had lafleur installed when I though I didn't and removing it stops reproducing. What a mess. Sorry again. I will spend a lot more time making sure any reports are reproducible.

    So here's how it's working for me:

    (release_jit_cpython_venv) :~ $ pip3 list
    Package    Version Editable project location
    ---------- ------- -----------------------------
    lafleur    0.0.1   /home/danzin/projects/lafleur
    peppercorn 0.6
    pip        25.1.1
    (release_jit_cpython_venv) :~ $ ~/venvs/release_jit_cpython_venv/bin/python ~/crashers/jit/reduced_crash_retcode_child_15732_2.py
    5
    5
    5
    5
    [... a bunch of numbers]
    427
    493
    35
    Segmentation fault (core dumped)
    

    I hope it works now.

  12. brandtbucher commented on Jul 22, 2025

    @brandtbucher
    brandtbucher
    on Jul 22, 2025
    Member
    More actions

    Also, for the future, setting a random seed really helps when randomness is involved. ;)

  13. devdanzin commented on Jul 22, 2025

    @devdanzin
    devdanzin
    on Jul 22, 2025
    MemberAuthor
    More actions

    Also, for the future, setting a random seed really helps when randomness is involved. ;)

    There's a seed for the mutations (that is, test case generation is reproducible), it just never occurred to me to add it to the fuzzing script (that is, doh)🤦. Thanks, will adopt it :)

    Are you able to reproduce it with latest instructions?

    Here's a small reduction I got, that shows calling randint isn't necessary:

    import gc
    gc.set_threshold(10)  # Doesn't seem to work with 1 or most numbers, but 10 works
    from random import randint  # Seems necessary to get GC to where we want
    
    
    class _EditableFinder:
        @classmethod
        def _find_spec(cls, fullname, candidate_path):
            pass
    
    
    class UnstableHash_unstable_hash_object_v4:
        def __hash__(self):
            print(5, end=" ", flush=True)  # If we don't flush, no crash. If we do a bare print, it also crashes.
            return 5
    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)]
            payload_val = obj.payload
            if callable(payload_val):
                payload_val()
    
        {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, 15, 17}:
            x, *y = tuple_v6
    
    for i_f1 in range(100):
            uop_harness_f1()
  14. brandtbucher commented on Jul 22, 2025

    @brandtbucher
    brandtbucher
    on Jul 22, 2025
    Member
    More actions

    Here's where I am:

    from importlib.machinery import all_suffixes as module_suffixes
    from importlib.util import spec_from_file_location
    
    class C:
        @classmethod
        def f():
            pass
    
    class D:
        def f(self):
            pass
    
    from random import randint
    from random import seed
    
    seed(5)
    
    # import gc
    
    # gc.set_threshold(1)
    
    class XXX:
        hash_count = 0
    
        def __hash__(self):
            self.hash_count += 1
            new_hash = None
            return randint(0, 1)
    
    xxx = XXX()
    tuple_v6 = (0,)
    
    def f():
    
        class W:
            payload = None
    
        class X:
            @property
            def payload(self):
                return 'property_payload'
    
        class Y:
            def payload(self):
                return id(self)
    
        class Z:
            __slots__ = ['payload']
            def __init__(self):
                self.payload = 'slot_payload'
    
        stuff = [W(), X(), Y(), Z()]
    
        for i in range(500):
            try:
                if callable(stuff[i % 4].payload):
                    pass
            except:
                pass
        {xxx, xxx, xxx, xxx, xxx, xxx}
        for i_loop_1589 in {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13}:
            x, *y = tuple_v6
    
    for i_f1 in range(88):
        f()
  15. Fidget-Spinner commented on Sep 1, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Sep 1, 2025
    Member
    More actions

    I can no longer repro on main. I think #136411 fixed this.

  16. Fidget-Spinner
    added
    3.14bugs and security fixesbugs and security fixes
    on Sep 1, 2025
  17. devdanzin commented on Sep 1, 2025

    @devdanzin
    devdanzin
    on Sep 1, 2025
    MemberAuthor
    More actions

    I can still repro on main by changing the gc tuning to gc.set_threshold(11) and raising number of iterations from 100 to 400. Does it abort for you too?

    import gc
    gc.set_threshold(11)  # Doesn't seem to work with 1 or most numbers, but 10 works
    from random import randint  # Seems necessary to get GC to where we want
    
    
    class _EditableFinder:
        @classmethod
        def _find_spec(cls, fullname, candidate_path):
            pass
    
    
    class UnstableHash_unstable_hash_object_v4:
        def __hash__(self):
            print(5, end=" ", flush=True)  # If we don't flush, no crash. If we do a bare print, it also crashes.
            return 5
    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)]
            payload_val = obj.payload
            if callable(payload_val):
                payload_val()
    
        {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, 15, 17}:
            x, *y = tuple_v6
    
    for i_f1 in range(400):
            uop_harness_f1()
  18. Fidget-Spinner commented on Sep 2, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Sep 2, 2025
    Member
    More actions

    I'm unable to repro with the given code.

  19. devdanzin commented on Sep 3, 2025

    @devdanzin
    devdanzin
    on Sep 3, 2025
    MemberAuthor
    More actions

    Hm, in another machine it only repros with gc.set_threshold(14). Can you try a few different values for that threshold if it still doesn't abort for you?

    Sorry for the fickle MRE.

  20. picnixz
    added a parent issue on Oct 11, 2025
    • JIT executors are not properly freed #139540
  21. Fidget-Spinner
    added a commit that references this issue on Dec 10, 2025

    gh-137007: Track executor before any possible deallocations (GH-137016)

    97e1901
  22. miss-islington
    added a commit that references this issue on Dec 10, 2025

    pythongh-137007: Track executor before any possible deallocations (py…

    25a48d9
  23. Fidget-Spinner
    added a commit that references this issue on Dec 10, 2025

    [3.14] gh-137007: Track executor before any possible deallocations (G…

    acd5b97
  24. Fidget-Spinner commented on Dec 11, 2025

    @Fidget-Spinner
    Fidget-Spinner
    on Dec 11, 2025
    Member
    More actions

    Since this can't be reproduced anymore, I'm closing the isssue.

  25. Fidget-Spinner
    closed this as completedon Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @Fidget-Spinner
    Fidget-Spinner

Labels

3.14bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-JITtype-crashA hard crash of the interpreter, possibly with a core dumpA 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

    You are visitor 01402520 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.