mirror of
https://github.com/python/cpython.git
synced 2026-10-28 18:35:21 +08:00
gh-156091: Fix crash compiling deeply nested inlined comprehensions (#156957)
This commit is contained in:
1 parent
ba4a0790aa
commit
14a93f4d91
4 files changed
+27
-2
No files matched your search
@@ -110,6 +110,7 @@ enum _PyCompile_FBlockType {
|
||||
COMPILE_FBLOCK_EXCEPTION_HANDLER,
|
||||
COMPILE_FBLOCK_EXCEPTION_GROUP_HANDLER,
|
||||
COMPILE_FBLOCK_ASYNC_COMPREHENSION_GENERATOR,
|
||||
COMPILE_FBLOCK_INLINED_COMPREHENSION,
|
||||
COMPILE_FBLOCK_STOP_ITERATION,
|
||||
};
|
||||
|
||||
|
||||
@@ -3519,6 +3519,21 @@ while 1:
|
||||
"""
|
||||
self._check_error(source, "too many statically nested blocks")
|
||||
|
||||
@support.cpython_only
|
||||
def test_nested_inlined_comprehensions_block_limit(self):
|
||||
# Each inlined comprehension with locals emits SETUP_FINALLY, which
|
||||
# must count toward CO_MAXBLOCKS (gh-156091).
|
||||
def src(depth):
|
||||
e = "i for i in r"
|
||||
for _ in range(depth - 1):
|
||||
e = "[" + e + "] for i in r"
|
||||
return "x = [" + e + "]"
|
||||
|
||||
CO_MAXBLOCKS = 21
|
||||
compile(src(CO_MAXBLOCKS), "<testcase>", "exec")
|
||||
self._check_error(src(CO_MAXBLOCKS + 1),
|
||||
"too many statically nested blocks")
|
||||
|
||||
@support.cpython_only
|
||||
def test_error_on_parser_stack_overflow(self):
|
||||
source = "-" * 100000 + "4"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Fix a crash when compiling deeply nested inlined list, set, or dict
|
||||
comprehensions. A :exc:`SyntaxError` is now raised when the nesting exceeds
|
||||
the compiler's static block limit.
|
||||
+8
-2
@@ -551,6 +551,7 @@ codegen_unwind_fblock(compiler *c, location *ploc,
|
||||
case COMPILE_FBLOCK_EXCEPTION_HANDLER:
|
||||
case COMPILE_FBLOCK_EXCEPTION_GROUP_HANDLER:
|
||||
case COMPILE_FBLOCK_ASYNC_COMPREHENSION_GENERATOR:
|
||||
case COMPILE_FBLOCK_INLINED_COMPREHENSION:
|
||||
case COMPILE_FBLOCK_STOP_ITERATION:
|
||||
return SUCCESS;
|
||||
|
||||
@@ -4976,8 +4977,11 @@ codegen_push_inlined_comprehension_locals(compiler *c, location loc,
|
||||
NEW_JUMP_TARGET_LABEL(c, cleanup);
|
||||
state->cleanup = cleanup;
|
||||
|
||||
// no need to push an fblock for this "virtual" try/finally; there can't
|
||||
// be return/continue/break inside a comprehension
|
||||
// Count against CO_MAXBLOCKS: SETUP_FINALLY consumes an except-stack
|
||||
// slot even though return/continue/break cannot appear here.
|
||||
RETURN_IF_ERROR(_PyCompile_PushFBlock(
|
||||
c, loc, COMPILE_FBLOCK_INLINED_COMPREHENSION,
|
||||
cleanup, NO_LABEL, NULL));
|
||||
ADDOP_JUMP(c, loc, SETUP_FINALLY, cleanup);
|
||||
}
|
||||
return SUCCESS;
|
||||
@@ -5023,6 +5027,8 @@ codegen_pop_inlined_comprehension_locals(compiler *c, location loc,
|
||||
{
|
||||
if (state->pushed_locals) {
|
||||
ADDOP(c, NO_LOCATION, POP_BLOCK);
|
||||
_PyCompile_PopFBlock(c, COMPILE_FBLOCK_INLINED_COMPREHENSION,
|
||||
state->cleanup);
|
||||
|
||||
NEW_JUMP_TARGET_LABEL(c, end);
|
||||
ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end);
|
||||
|
||||
Reference in new issue
Block a user