From 02d126aa09d96d03dcf9c5b51c858ce5ef386601 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 25 Sep 2020 14:04:19 +0100 Subject: [PATCH] bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395) * Account for control blocks in 'except' in compiler. Fixes #39934. --- Lib/test/test_syntax.py | 9 +++++++++ .../2020-09-24-12-15-45.bpo-39934.YVHTCF.rst | 3 +++ Python/compile.c | 19 +++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-09-24-12-15-45.bpo-39934.YVHTCF.rst diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 4657fd1c0d8..09c6eb33754 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -950,6 +950,15 @@ pass 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 00000000000..92cd1ba234d --- /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 0f9e5c276c7..f2563d7f7a4 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);