Skip to content

Commit 6ce1a15

Browse files
[3.13] gh-156091: Fix crash compiling deeply nested inlined comprehensions (GH-156957)
Count inlined-comprehension SETUP_FINALLY handlers toward CO_MAXBLOCKS. Manual backport of 14a93f4 / GH-156993; 3.13 still has this code in compile.c. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 19693af commit 6ce1a15

3 files changed

Lines changed: 25 additions & 3 deletions

File tree

Lib/test/test_syntax.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,21 @@ def test_syntax_error_on_deeply_nested_blocks(self):
26972697
"""
26982698
self._check_error(source, "too many statically nested blocks")
26992699

2700+
@support.cpython_only
2701+
def test_nested_inlined_comprehensions_block_limit(self):
2702+
# Each inlined comprehension with locals emits SETUP_FINALLY, which
2703+
# must count toward CO_MAXBLOCKS (gh-156091).
2704+
def src(depth):
2705+
e = "i for i in r"
2706+
for _ in range(depth - 1):
2707+
e = "[" + e + "] for i in r"
2708+
return "x = [" + e + "]"
2709+
2710+
CO_MAXBLOCKS = 21
2711+
compile(src(CO_MAXBLOCKS), "<testcase>", "exec")
2712+
self._check_error(src(CO_MAXBLOCKS + 1),
2713+
"too many statically nested blocks")
2714+
27002715
@support.cpython_only
27012716
def test_error_on_parser_stack_overflow(self):
27022717
source = "-" * 100000 + "4"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash when compiling deeply nested inlined list, set, or dict
2+
comprehensions. A :exc:`SyntaxError` is now raised when the nesting exceeds
3+
the compiler's static block limit.

Python/compile.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ compiler IR.
114114
enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
115115
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER,
116116
EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR,
117-
STOP_ITERATION };
117+
INLINED_COMPREHENSION, STOP_ITERATION };
118118

119119
struct fblockinfo {
120120
enum fblocktype fb_type;
@@ -1523,6 +1523,7 @@ compiler_unwind_fblock(struct compiler *c, location *ploc,
15231523
case EXCEPTION_HANDLER:
15241524
case EXCEPTION_GROUP_HANDLER:
15251525
case ASYNC_COMPREHENSION_GENERATOR:
1526+
case INLINED_COMPREHENSION:
15261527
case STOP_ITERATION:
15271528
return SUCCESS;
15281529

@@ -5714,8 +5715,10 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
57145715
NEW_JUMP_TARGET_LABEL(c, end);
57155716
state->end = end;
57165717

5717-
// no need to push an fblock for this "virtual" try/finally; there can't
5718-
// be return/continue/break inside a comprehension
5718+
// Count against CO_MAXBLOCKS: SETUP_FINALLY consumes an except-stack
5719+
// slot even though return/continue/break cannot appear here.
5720+
RETURN_IF_ERROR(compiler_push_fblock(c, loc, INLINED_COMPREHENSION,
5721+
cleanup, NO_LABEL, NULL));
57195722
ADDOP_JUMP(c, loc, SETUP_FINALLY, cleanup);
57205723
}
57215724

@@ -5761,6 +5764,7 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
57615764
}
57625765
if (state.pushed_locals) {
57635766
ADDOP(c, NO_LOCATION, POP_BLOCK);
5767+
compiler_pop_fblock(c, INLINED_COMPREHENSION, state.cleanup);
57645768
ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, state.end);
57655769

57665770
// cleanup from an exception inside the comprehension

0 commit comments

Comments
 (0)