[3.14] gh-137883: Check the recursion limit for specialized keyword argument calls (GH-137887) (#137945)
Some checks failed
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Check if the ABI has changed (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Android (aarch64) (push) Blocked by required conditions
Tests / Android (x86_64) (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Lint / lint (push) Waiting to run
JIT / Interpreter (Debug) (push) Has been cancelled
Tail calling interpreter / aarch64-apple-darwin/clang (push) Has been cancelled
Tail calling interpreter / aarch64-unknown-linux-gnu/gcc (push) Has been cancelled
Tail calling interpreter / x86_64-pc-windows-msvc/msvc (push) Has been cancelled
Tail calling interpreter / x86_64-apple-darwin/clang (push) Has been cancelled
Tail calling interpreter / free-threading (push) Has been cancelled
Tail calling interpreter / x86_64-unknown-linux-gnu/gcc (push) Has been cancelled
JIT / aarch64-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / aarch64-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
JIT / i686-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / i686-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
JIT / aarch64-apple-darwin/clang (Release) (push) Has been cancelled
JIT / aarch64-unknown-linux-gnu/gcc (Release) (push) Has been cancelled
JIT / aarch64-apple-darwin/clang (Debug) (push) Has been cancelled
JIT / aarch64-unknown-linux-gnu/gcc (Debug) (push) Has been cancelled
JIT / x86_64-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / x86_64-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
JIT / x86_64-apple-darwin/clang (Release) (push) Has been cancelled
JIT / x86_64-unknown-linux-gnu/gcc (Release) (push) Has been cancelled
JIT / x86_64-apple-darwin/clang (Debug) (push) Has been cancelled
JIT / x86_64-unknown-linux-gnu/gcc (Debug) (push) Has been cancelled

Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
Peter Bierma 2025-08-25 12:19:39 -04:00 committed by GitHub
parent 9fa74c57fe
commit 8b3f9ae2ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 19 additions and 1 deletions

View file

@ -1366,7 +1366,7 @@ _PyOpcode_macro_expansion[256] = {
[CALL_ISINSTANCE] = { .nuops = 1, .uops = { { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, [CALL_ISINSTANCE] = { .nuops = 1, .uops = { { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } },
[CALL_KW_BOUND_METHOD] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION_KW, 2, 1 }, { _EXPAND_METHOD_KW, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_KW_BOUND_METHOD] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION_KW, 2, 1 }, { _EXPAND_METHOD_KW, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_KW_NON_PY] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_KW, OPARG_SIMPLE, 3 }, { _CALL_KW_NON_PY, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_KW_NON_PY] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_KW, OPARG_SIMPLE, 3 }, { _CALL_KW_NON_PY, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } },
[CALL_KW_PY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_KW_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_LEN] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 } } }, [CALL_LEN] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 } } },
[CALL_LIST_APPEND] = { .nuops = 1, .uops = { { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } }, [CALL_LIST_APPEND] = { .nuops = 1, .uops = { { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } },

View file

@ -1074,6 +1074,14 @@ class TestRecursion(unittest.TestCase):
with self.assertRaises(RecursionError): with self.assertRaises(RecursionError):
c_py_recurse(100_000) c_py_recurse(100_000)
def test_recursion_with_kwargs(self):
# GH-137883: The interpreter forgot to check the recursion limit when
# calling with keywords.
def recurse_kw(a=0):
recurse_kw(a=0)
with self.assertRaises(RecursionError):
recurse_kw()
class TestFunctionWithManyArgs(unittest.TestCase): class TestFunctionWithManyArgs(unittest.TestCase):
def test_function_with_many_args(self): def test_function_with_many_args(self):

View file

@ -0,0 +1 @@
Fix runaway recursion when calling a function with keyword arguments.

View file

@ -4740,6 +4740,7 @@ dummy_func(
unused/1 + // Skip over the counter unused/1 + // Skip over the counter
_CHECK_PEP_523 + _CHECK_PEP_523 +
_CHECK_FUNCTION_VERSION_KW + _CHECK_FUNCTION_VERSION_KW +
_CHECK_RECURSION_REMAINING +
_PY_FRAME_KW + _PY_FRAME_KW +
_SAVE_RETURN_OFFSET + _SAVE_RETURN_OFFSET +
_PUSH_FRAME; _PUSH_FRAME;

View file

@ -3324,6 +3324,14 @@
JUMP_TO_PREDICTED(CALL_KW); JUMP_TO_PREDICTED(CALL_KW);
} }
} }
// _CHECK_RECURSION_REMAINING
{
if (tstate->py_recursion_remaining <= 1) {
UPDATE_MISS_STATS(CALL_KW);
assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
JUMP_TO_PREDICTED(CALL_KW);
}
}
// _PY_FRAME_KW // _PY_FRAME_KW
{ {
kwnames = stack_pointer[-1]; kwnames = stack_pointer[-1];