https://github.com/python/cpython/commit/277a03711b1d712c1a4881f07705498c07ebf957
commit: 277a03711b1d712c1a4881f07705498c07ebf957
branch: main
author: Hai Zhu <[email protected]>
committer: markshannon <[email protected]>
date: 2026-02-25T16:52:53Z
summary:

gh-145197: Fix JIT trace crash when recording function from cleared generator 
frame (GH-145220)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-02-25-15-02-08.gh-issue-145197.G6hAUk.rst
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_uop_metadata.h
M Lib/test/test_capi/test_opt.py
M Python/bytecodes.c
M Python/record_functions.c.h

diff --git a/Include/internal/pycore_opcode_metadata.h 
b/Include/internal/pycore_opcode_metadata.h
index fa8337bd08d470..126bc7d7102925 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -1179,7 +1179,7 @@ const struct opcode_metadata 
_PyOpcode_opcode_metadata[267] = {
     [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG 
},
     [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG },
     [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | 
HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | 
HAS_UNPREDICTABLE_JUMP_FLAG },
-    [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | 
HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | 
HAS_RECORDS_VALUE_FLAG },
+    [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | 
HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
     [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | 
HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG 
},
     [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | 
HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
     [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | 
HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
@@ -1283,7 +1283,7 @@ const struct opcode_metadata 
_PyOpcode_opcode_metadata[267] = {
     [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
     [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | 
HAS_NEEDS_GUARD_IP_FLAG },
     [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | 
HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
-    [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | 
HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | 
HAS_RECORDS_VALUE_FLAG },
+    [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | 
HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
     [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG },
     [SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG },
     [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
diff --git a/Include/internal/pycore_uop_metadata.h 
b/Include/internal/pycore_uop_metadata.h
index be06738b54ca67..33a4d17d766eb2 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -379,7 +379,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_RECORD_TOS] = HAS_RECORDS_VALUE_FLAG,
     [_RECORD_TOS_TYPE] = HAS_RECORDS_VALUE_FLAG,
     [_RECORD_NOS] = HAS_RECORDS_VALUE_FLAG,
-    [_RECORD_NOS_GEN_FUNC] = HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG,
+    [_RECORD_NOS_GEN_FUNC] = HAS_RECORDS_VALUE_FLAG,
     [_RECORD_4OS] = HAS_RECORDS_VALUE_FLAG,
     [_RECORD_CALLABLE] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
     [_RECORD_BOUND_METHOD] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index fe1b45608841a2..90e2ed20d1f6b3 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -4114,6 +4114,28 @@ def __init__(self, name):
              PYTHON_JIT_SIDE_EXIT_INITIAL_VALUE="1")
         self.assertEqual(result[0].rc, 0, result)
 
+    def test_for_iter_gen_cleared_frame_does_not_crash(self):
+        # See: https://github.com/python/cpython/issues/145197
+        result = script_helper.run_python_until_end('-c', textwrap.dedent("""
+        def g():
+            yield 1
+            yield 2
+
+        for _ in range(4002):
+            for _ in g():
+                pass
+
+        for i in range(4002):
+            it = g()
+            if (i & 7) == 0:
+                next(it)
+                it.close()
+            for _ in it:
+                pass
+        """),
+        PYTHON_JIT="1", PYTHON_JIT_STRESS="1")
+        self.assertEqual(result[0].rc, 0, result)
+
 def global_identity(x):
     return x
 
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-25-15-02-08.gh-issue-145197.G6hAUk.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-25-15-02-08.gh-issue-145197.G6hAUk.rst
new file mode 100644
index 00000000000000..6d6afe5abfea9c
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-25-15-02-08.gh-issue-145197.G6hAUk.rst
@@ -0,0 +1 @@
+Fix JIT trace crash when recording function from cleared generator frame.
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 36af61412b7417..41323c4f54d9ed 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -5730,8 +5730,11 @@ dummy_func(
         tier2 op(_RECORD_NOS_GEN_FUNC, (nos, tos -- nos, tos)) {
             PyObject *obj = PyStackRef_AsPyObjectBorrow(nos);
             if (PyGen_Check(obj)) {
-                PyObject *func = (PyObject 
*)_PyFrame_GetFunction(&((PyGenObject *)obj)->gi_iframe);
-                RECORD_VALUE(func);
+                PyGenObject *gen = (PyGenObject *)obj;
+                _PyStackRef func = gen->gi_iframe.f_funcobj;
+                if (!PyStackRef_IsNull(func)) {
+                    RECORD_VALUE(PyStackRef_AsPyObjectBorrow(func));
+                }
             }
         }
 
diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h
index c6709f9a9d6bec..64cafcb326e111 100644
--- a/Python/record_functions.c.h
+++ b/Python/record_functions.c.h
@@ -32,11 +32,12 @@ void 
_PyOpcode_RecordFunction_NOS_GEN_FUNC(_PyInterpreterFrame *frame, _PyStackR
     nos = stack_pointer[-2];
     PyObject *obj = PyStackRef_AsPyObjectBorrow(nos);
     if (PyGen_Check(obj)) {
-        _PyFrame_SetStackPointer(frame, stack_pointer);
-        PyObject *func = (PyObject *)_PyFrame_GetFunction(&((PyGenObject 
*)obj)->gi_iframe);
-        stack_pointer = _PyFrame_GetStackPointer(frame);
-        *recorded_value = (PyObject *)func;
-        Py_INCREF(*recorded_value);
+        PyGenObject *gen = (PyGenObject *)obj;
+        _PyStackRef func = gen->gi_iframe.f_funcobj;
+        if (!PyStackRef_IsNull(func)) {
+            *recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(func);
+            Py_INCREF(*recorded_value);
+        }
     }
 }
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to