[Python-checkins] bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395)

Mark Shannon webhook-mailer at python.org
Fri Sep 25 09:04:29 EDT 2020


https://github.com/python/cpython/commit/02d126aa09d96d03dcf9c5b51c858ce5ef386601
commit: 02d126aa09d96d03dcf9c5b51c858ce5ef386601
branch: master
author: Mark Shannon <mark at hotpy.org>
committer: GitHub <noreply at github.com>
date: 2020-09-25T14:04:19+01:00
summary:

bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395)

* Account for control blocks in 'except' in compiler. Fixes #39934.

files:
A Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.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 4657fd1c0d8a7..09c6eb3375409 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -950,6 +950,15 @@ def test_empty_line_after_linecont(self):
         except SyntaxError:
             self.fail("Empty line after a line continuation character is valid.")
 
+    @support.cpython_only
+    def test_nested_named_except_blocks(self):
+        code = ""
+        for i in range(12):
+            code += f"{'    '*i}try:\n"
+            code += f"{'    '*(i+1)}raise Exception\n"
+            code += f"{'    '*i}except Exception as e:\n"
+        code += f"{' '*4*12}pass"
+        self._check_error(code, "too many statically nested blocks")
 
 def test_main():
     support.run_unittest(SyntaxTestCase)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst b/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst
new file mode 100644
index 0000000000000..92cd1ba234d21
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst	
@@ -0,0 +1,3 @@
+Correctly count control blocks in 'except' in compiler. Ensures that a
+syntax error, rather a fatal error, occurs for deeply nested, named
+exception handlers.
diff --git a/Python/compile.c b/Python/compile.c
index 0f9e5c276c7b7..f2563d7f7a411 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -108,8 +108,8 @@ It's called a frame block to distinguish it from a basic block in the
 compiler IR.
 */
 
-enum fblocktype { WHILE_LOOP, FOR_LOOP, EXCEPT, FINALLY_TRY, FINALLY_END,
-                  WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE };
+enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
+                  WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER };
 
 struct fblockinfo {
     enum fblocktype fb_type;
@@ -1623,9 +1623,7 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
 {
     struct fblockinfo *f;
     if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
-        PyErr_SetString(PyExc_SyntaxError,
-                        "too many statically nested blocks");
-        return 0;
+        return compiler_error(c, "too many statically nested blocks");
     }
     f = &c->u->u_fblock[c->u->u_nfblocks++];
     f->fb_type = t;
@@ -1665,6 +1663,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
 {
     switch (info->fb_type) {
         case WHILE_LOOP:
+        case EXCEPTION_HANDLER:
             return 1;
 
         case FOR_LOOP:
@@ -1675,7 +1674,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
             ADDOP(c, POP_TOP);
             return 1;
 
-        case EXCEPT:
+        case TRY_EXCEPT:
             ADDOP(c, POP_BLOCK);
             return 1;
 
@@ -3060,14 +3059,17 @@ compiler_try_except(struct compiler *c, stmt_ty s)
         return 0;
     ADDOP_JUMP(c, SETUP_FINALLY, except);
     compiler_use_next_block(c, body);
-    if (!compiler_push_fblock(c, EXCEPT, body, NULL, NULL))
+    if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL))
         return 0;
     VISIT_SEQ(c, stmt, s->v.Try.body);
     ADDOP(c, POP_BLOCK);
-    compiler_pop_fblock(c, EXCEPT, body);
+    compiler_pop_fblock(c, TRY_EXCEPT, body);
     ADDOP_JUMP(c, JUMP_FORWARD, orelse);
     n = asdl_seq_LEN(s->v.Try.handlers);
     compiler_use_next_block(c, except);
+    /* Runtime will push a block here, so we need to account for that */
+    if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL))
+        return 0;
     for (i = 0; i < n; i++) {
         excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
             s->v.Try.handlers, i);
@@ -3152,6 +3154,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
         }
         compiler_use_next_block(c, except);
     }
+    compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL);
     ADDOP(c, RERAISE);
     compiler_use_next_block(c, orelse);
     VISIT_SEQ(c, stmt, s->v.Try.orelse);



More information about the Python-checkins mailing list