mirror of
https://github.com/python/cpython.git
synced 2025-11-08 17:41:42 +00:00
gh-137883: Check the recursion limit for specialized keyword argument calls (GH-137887)
This commit is contained in:
parent
bb75dec87f
commit
b07a267953
5 changed files with 19 additions and 1 deletions
2
Include/internal/pycore_opcode_metadata.h
generated
2
Include/internal/pycore_opcode_metadata.h
generated
|
|
@ -1354,7 +1354,7 @@ _PyOpcode_macro_expansion[256] = {
|
||||||
[CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } },
|
[CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _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_AT_END, OPARG_REPLACED, 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_AT_END, OPARG_REPLACED, 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 = 4, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } },
|
[CALL_LIST_APPEND] = { .nuops = 4, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } },
|
||||||
[CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
|
[CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
|
||||||
|
|
|
||||||
|
|
@ -1074,6 +1074,14 @@ def c_py_recurse(m):
|
||||||
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):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix runaway recursion when calling a function with keyword arguments.
|
||||||
|
|
@ -4721,6 +4721,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;
|
||||||
|
|
|
||||||
8
Python/generated_cases.c.h
generated
8
Python/generated_cases.c.h
generated
|
|
@ -3277,6 +3277,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];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue