https://github.com/python/cpython/commit/dd36d014da20f6217f0ae729450dd79745545927
commit: dd36d014da20f6217f0ae729450dd79745545927
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: iritkatriel <[email protected]>
date: 2026-09-05T16:27:05Z
summary:

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

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

diff --git a/Include/internal/pycore_compile.h 
b/Include/internal/pycore_compile.h
index ed776bbb73a0ee9..193d5d180a3c8cf 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -106,6 +106,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,
 };
 
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index de8c94fe8d2d18c..c11822333f4c7eb 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -3225,6 +3225,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/codegen.c b/Python/codegen.c
index f90ec1756cdeab5..0aa9995b4f087f3 100644
--- a/Python/codegen.c
+++ b/Python/codegen.c
@@ -527,6 +527,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;
 
@@ -4685,8 +4686,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;
@@ -4732,6 +4736,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);

_______________________________________________
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