https://github.com/python/cpython/commit/85f8e767058c847f9f2b70ebb9625102a15ee382
commit: 85f8e767058c847f9f2b70ebb9625102a15ee382
branch: 3.13
author: Ken Jin <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2026-03-03T04:09:02+08:00
summary:

[3.13] gh-145008: Maintain stack consistency in CALL_BOUND_METHOD_EXACT_ARGS 
(GH-145015)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-02-19-19-23-12.gh-issue-145008.tHYQv6.rst
M Include/internal/pycore_opcode_metadata.h
M Python/bytecodes.c
M Python/generated_cases.c.h

diff --git a/Include/internal/pycore_opcode_metadata.h 
b/Include/internal/pycore_opcode_metadata.h
index a3d31bcbc4ab54..610e3cc2f2024d 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -1221,7 +1221,7 @@ _PyOpcode_macro_expansion[256] = {
     [BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, 0, 0 } } },
     [BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, 0, 0 } } },
     [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 
0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { 
_INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 
}, { _CHECK_STACK_SPACE, 0, 0 }, { _CHECK_RECURSION_REMAINING, 0, 0 }, { 
_INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 
0, 0 } } },
-    [CALL_BOUND_METHOD_GENERAL] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 
0 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, 0, 0 }, { 
_CHECK_RECURSION_REMAINING, 0, 0 }, { _PY_FRAME_GENERAL, 0, 0 }, { 
_SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } },
+    [CALL_BOUND_METHOD_GENERAL] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 
0 }, { _CHECK_RECURSION_REMAINING, 0, 0 }, { _CHECK_METHOD_VERSION, 2, 1 }, { 
_EXPAND_METHOD, 0, 0 }, { _PY_FRAME_GENERAL, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 
3 }, { _PUSH_FRAME, 0, 0 } } },
     [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, 0, 0 
}, { _CHECK_PERIODIC, 0, 0 } } },
     [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, 0, 0 
}, { _CHECK_PERIODIC, 0, 0 } } },
     [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { 
_CALL_BUILTIN_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } },
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-19-19-23-12.gh-issue-145008.tHYQv6.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-19-19-23-12.gh-issue-145008.tHYQv6.rst
new file mode 100644
index 00000000000000..d378d2acb6924a
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-19-19-23-12.gh-issue-145008.tHYQv6.rst
@@ -0,0 +1 @@
+Fix a bug when calling certain methods at the recursion limit which manifested 
as a corruption of Python's operand stack. Patch by Ken Jin.
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 42cddac048f3f6..24568489f2d25d 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3241,9 +3241,11 @@ dummy_func(
         macro(CALL_BOUND_METHOD_GENERAL) =
             unused/1 + // Skip over the counter
             _CHECK_PEP_523 +
+            // gh-145008: We must check recursion before expanding method,
+            // otherwise we may leave the stack in an inconsistent state in 
3.13.
+            _CHECK_RECURSION_REMAINING +
             _CHECK_METHOD_VERSION +
             _EXPAND_METHOD +
-            _CHECK_RECURSION_REMAINING +
             _PY_FRAME_GENERAL +
             _SAVE_RETURN_OFFSET +
             _PUSH_FRAME;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index d21499b2f5724a..ad49becdfcaa67 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -1024,6 +1024,10 @@
             {
                 DEOPT_IF(tstate->interp->eval_frame, CALL);
             }
+            // _CHECK_RECURSION_REMAINING
+            {
+                DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL);
+            }
             // _CHECK_METHOD_VERSION
             null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
@@ -1047,10 +1051,6 @@
                 Py_INCREF(method);
                 Py_DECREF(callable);
             }
-            // _CHECK_RECURSION_REMAINING
-            {
-                DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL);
-            }
             // _PY_FRAME_GENERAL
             args = &stack_pointer[-oparg];
             self_or_null = self;

_______________________________________________
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