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]