GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||
GeezerVison is showing github.com — gh-155151: Check the recursion limit in CALL_EX_PY and CALL_KW_BOUND_METHOD by tekinertekin · Pull Request #155272 · python/cpython Conversation
|
| case | opcode | before | after |
|---|---|---|---|
| call-ex | CALL_FUNCTION_EX (control) |
RecursionError, 0 executions | unchanged |
| call-ex | CALL_EX_PY (specialized) |
returned 42, 1 execution | RecursionError, 0 executions |
| call-kw-bound-method | CALL_KW (control) |
RecursionError, 0 executions | unchanged |
| call-kw-bound-method | CALL_KW_BOUND_METHOD (specialized) |
returned 43, 1 execution | RecursionError, 0 executions |
The call sites still specialize afterwards — dis(..., adaptive=True) still
reports CALL_EX_PY and CALL_KW_BOUND_METHOD, so this adds the check rather
than suppressing the specialization.
Two regression tests were added next to test_recursion_check_for_general_calls
in test_opcache.py. They warm the call site, assert it specialized, then make
the call from the deepest live frame at the recursion limit and assert the
target never ran. Both fail on unpatched main with AssertionError: RecursionError not raised. The targets bump the counter with plain bytecode
rather than through another call, so reaching them cannot be masked by a second
recursion check.
test_opcache passes (84 tests), including under -R 3:3. test_call,
test_dis, test_generated_cases, test_monitoring, test_optimizer,
test_sys_settrace and test_capi pass. Tools/patchcheck is clean.
I did not build with --enable-experimental-jit locally, so the JIT job here
will be the first check of the tier 2 side.
AI tools were used on this PR: Claude Code (Opus) reproduced the issue, wrote
the patch and the tests, and ran the verification above. I reviewed the change,
understand it and can explain it, and I take responsibility for it.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…BOUND_METHOD The generic CALL_FUNCTION_EX and CALL_KW opcodes reach start_frame, which calls _Py_EnterRecursivePy() and raises RecursionError before the callee runs. Their specialized forms end in _PUSH_FRAME, which decrements py_recursion_remaining without checking it, so once a call site had been warmed up the callee was entered and returned normally where the unspecialized instruction raised. Warming a call site should not change whether the target function executes. CALL_KW_PY and CALL_BOUND_METHOD_EXACT_ARGS already guard their frame push with _CHECK_RECURSION_REMAINING; add it to these two as well. It deopts, so it goes where a deopt is already safe: after the existing flush in CALL_KW_BOUND_METHOD, following the pattern of CALL_BOUND_METHOD_EXACT_ARGS, and after _CHECK_IS_PY_CALLABLE_EX in CALL_EX_PY, which already exits at that point.
|
The description of this PR and #155269 is almost identical, and thus even the description was probably generated entirely by an agent. In particular, I consider this as an excessive use of agents and will reject this PR especially since it touches the core interpreter. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
CALL_EX_PY and CALL_KW_BOUND_METHOD can bypass RecursionError after specialization
There was an error while loading. Please reload this page.