https://github.com/python/cpython/commit/c341e341b25cec03d28d1b2c368bb871d76ca88b
commit: c341e341b25cec03d28d1b2c368bb871d76ca88b
branch: main
author: Hai Zhu <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-05-08T11:20:27Z
summary:
gh-149459: Fix segfault when `_LOAD_SPECIAL` guard deoptimizes (#149478)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst
M Lib/test/test_capi/test_opt.py
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index aaa5050208ced9..2f606c2c6eba2d 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -6138,6 +6138,20 @@ def __init__(self, x):
C(0) if i else str(0)
"""))
+ def test_load_special_type_guard_deopt(self):
+ script_helper.assert_python_ok("-s", "-c", textwrap.dedent(f"""
+ def f1():
+ class Context:
+ def __enter__(self): ...
+ def __exit__(self, e, v, t): ...
+
+ with Context():
+ pass
+
+ for _ in range({TIER2_THRESHOLD + 5}):
+ f1()
+ """), PYTHON_JIT="1")
+
def global_identity(x):
return x
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst
new file mode 100644
index 00000000000000..4cd0a148df3c70
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-07-03-18-59.gh-issue-149459.5fhAqP.rst
@@ -0,0 +1 @@
+Fix a crash in the JIT optimizer when a specialized ``LOAD_SPECIAL`` guard
deoptimized after inserting the synthetic ``NULL`` stack entry.
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 39cc36ae79fead..96dbaea5a5797e 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -2043,7 +2043,16 @@ dummy_func(void) {
PyObject *name = _Py_SpecialMethods[oparg].name;
PyObject *descr = _PyType_Lookup(type, name);
if (descr != NULL && (Py_TYPE(descr)->tp_flags &
Py_TPFLAGS_METHOD_DESCRIPTOR)) {
- ADD_OP(_GUARD_TYPE_VERSION, 0, type->tp_version_tag);
+ /* LOAD_SPECIAL expands to _RECORD_TOS_TYPE + _INSERT_NULL +
+ * _LOAD_SPECIAL. Insert _GUARD_TYPE_VERSION before the
+ * already-emitted _INSERT_NULL so deopt sees the original
+ * stack shape.*/
+ _PyUOpInstruction *insert_null =
uop_buffer_last(&ctx->out_buffer);
+ assert(insert_null->opcode == _INSERT_NULL);
+ assert(insert_null->target == this_instr->target);
+ REPLACE_OP(insert_null, _GUARD_TYPE_VERSION, 0,
type->tp_version_tag);
+ ADD_OP(_INSERT_NULL, 0, 0);
+
bool immortal = _Py_IsImmortal(descr) || (type->tp_flags &
Py_TPFLAGS_IMMUTABLETYPE);
ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW :
_LOAD_CONST_INLINE,
0, (uintptr_t)descr);
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index db3dcbb97b2645..f336549d2ed244 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -3896,7 +3896,11 @@
PyObject *name = _Py_SpecialMethods[oparg].name;
PyObject *descr = _PyType_Lookup(type, name);
if (descr != NULL && (Py_TYPE(descr)->tp_flags &
Py_TPFLAGS_METHOD_DESCRIPTOR)) {
- ADD_OP(_GUARD_TYPE_VERSION, 0, type->tp_version_tag);
+ _PyUOpInstruction *insert_null =
uop_buffer_last(&ctx->out_buffer);
+ assert(insert_null->opcode == _INSERT_NULL);
+ assert(insert_null->target == this_instr->target);
+ REPLACE_OP(insert_null, _GUARD_TYPE_VERSION, 0,
type->tp_version_tag);
+ ADD_OP(_INSERT_NULL, 0, 0);
bool immortal = _Py_IsImmortal(descr) || (type->tp_flags &
Py_TPFLAGS_IMMUTABLETYPE);
ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW :
_LOAD_CONST_INLINE,
0, (uintptr_t)descr);
_______________________________________________
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]