https://github.com/python/cpython/commit/d7657d0e1850f90624ea8be63d6fdb5a8dd3e497
commit: d7657d0e1850f90624ea8be63d6fdb5a8dd3e497
branch: 3.13
author: Irit Katriel <[email protected]>
committer: iritkatriel <[email protected]>
date: 2026-09-17T19:14:25+01:00
summary:

[3.13] gh-156091: Fix crash compiling deeply nested inlined comprehensions 
(GH-156957) (#157050)

Count inlined-comprehension SETUP_FINALLY handlers toward CO_MAXBLOCKS.
Manual backport of 14a93f4d91ed / GH-156993; 3.13 still has this code in 
compile.c.

Co-authored-by: Cursor <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-09-04-14-06-00.gh-issue-156091.nested-comp.rst
M Lib/test/test_syntax.py
M Python/compile.c

diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index b035883cf883b93..a7c043a055e59d1 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -2697,6 +2697,21 @@ def test_syntax_error_on_deeply_nested_blocks(self):
 """
         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"
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-04-14-06-00.gh-issue-156091.nested-comp.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-04-14-06-00.gh-issue-156091.nested-comp.rst
new file mode 100644
index 000000000000000..fdceb3209b7f7cb
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-04-14-06-00.gh-issue-156091.nested-comp.rst
@@ -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.
diff --git a/Python/compile.c b/Python/compile.c
index 9151c29a9c1862d..a0b7df0870e8267 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -114,7 +114,7 @@ compiler IR.
 enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
                   WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, 
EXCEPTION_HANDLER,
                   EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR,
-                  STOP_ITERATION };
+                  INLINED_COMPREHENSION, STOP_ITERATION };
 
 struct fblockinfo {
     enum fblocktype fb_type;
@@ -1523,6 +1523,7 @@ compiler_unwind_fblock(struct compiler *c, location *ploc,
         case EXCEPTION_HANDLER:
         case EXCEPTION_GROUP_HANDLER:
         case ASYNC_COMPREHENSION_GENERATOR:
+        case INLINED_COMPREHENSION:
         case STOP_ITERATION:
             return SUCCESS;
 
@@ -5714,8 +5715,10 @@ push_inlined_comprehension_state(struct compiler *c, 
location loc,
         NEW_JUMP_TARGET_LABEL(c, end);
         state->end = end;
 
-        // 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(compiler_push_fblock(c, loc, INLINED_COMPREHENSION,
+                                             cleanup, NO_LABEL, NULL));
         ADDOP_JUMP(c, loc, SETUP_FINALLY, cleanup);
     }
 
@@ -5761,6 +5764,7 @@ pop_inlined_comprehension_state(struct compiler *c, 
location loc,
     }
     if (state.pushed_locals) {
         ADDOP(c, NO_LOCATION, POP_BLOCK);
+        compiler_pop_fblock(c, INLINED_COMPREHENSION, state.cleanup);
         ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, state.end);
 
         // cleanup from an exception inside the comprehension

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to