Skip to content

Commit 02d126a

Browse files
authored
bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395)
* Account for control blocks in 'except' in compiler. Fixes #39934.
1 parent 05cc881 commit 02d126a

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

Lib/test/test_syntax.py

+9
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,15 @@ def test_empty_line_after_linecont(self):
950950
except SyntaxError:
951951
self.fail("Empty line after a line continuation character is valid.")
952952

953+
@support.cpython_only
954+
def test_nested_named_except_blocks(self):
955+
code = ""
956+
for i in range(12):
957+
code += f"{' '*i}try:\n"
958+
code += f"{' '*(i+1)}raise Exception\n"
959+
code += f"{' '*i}except Exception as e:\n"
960+
code += f"{' '*4*12}pass"
961+
self._check_error(code, "too many statically nested blocks")
953962

954963
def test_main():
955964
support.run_unittest(SyntaxTestCase)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Correctly count control blocks in 'except' in compiler. Ensures that a
2+
syntax error, rather a fatal error, occurs for deeply nested, named
3+
exception handlers.

Python/compile.c

+11-8
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ It's called a frame block to distinguish it from a basic block in the
108108
compiler IR.
109109
*/
110110

111-
enum fblocktype { WHILE_LOOP, FOR_LOOP, EXCEPT, FINALLY_TRY, FINALLY_END,
112-
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE };
111+
enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
112+
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER };
113113

114114
struct fblockinfo {
115115
enum fblocktype fb_type;
@@ -1623,9 +1623,7 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
16231623
{
16241624
struct fblockinfo *f;
16251625
if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
1626-
PyErr_SetString(PyExc_SyntaxError,
1627-
"too many statically nested blocks");
1628-
return 0;
1626+
return compiler_error(c, "too many statically nested blocks");
16291627
}
16301628
f = &c->u->u_fblock[c->u->u_nfblocks++];
16311629
f->fb_type = t;
@@ -1665,6 +1663,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
16651663
{
16661664
switch (info->fb_type) {
16671665
case WHILE_LOOP:
1666+
case EXCEPTION_HANDLER:
16681667
return 1;
16691668

16701669
case FOR_LOOP:
@@ -1675,7 +1674,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
16751674
ADDOP(c, POP_TOP);
16761675
return 1;
16771676

1678-
case EXCEPT:
1677+
case TRY_EXCEPT:
16791678
ADDOP(c, POP_BLOCK);
16801679
return 1;
16811680

@@ -3060,14 +3059,17 @@ compiler_try_except(struct compiler *c, stmt_ty s)
30603059
return 0;
30613060
ADDOP_JUMP(c, SETUP_FINALLY, except);
30623061
compiler_use_next_block(c, body);
3063-
if (!compiler_push_fblock(c, EXCEPT, body, NULL, NULL))
3062+
if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL))
30643063
return 0;
30653064
VISIT_SEQ(c, stmt, s->v.Try.body);
30663065
ADDOP(c, POP_BLOCK);
3067-
compiler_pop_fblock(c, EXCEPT, body);
3066+
compiler_pop_fblock(c, TRY_EXCEPT, body);
30683067
ADDOP_JUMP(c, JUMP_FORWARD, orelse);
30693068
n = asdl_seq_LEN(s->v.Try.handlers);
30703069
compiler_use_next_block(c, except);
3070+
/* Runtime will push a block here, so we need to account for that */
3071+
if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL))
3072+
return 0;
30713073
for (i = 0; i < n; i++) {
30723074
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
30733075
s->v.Try.handlers, i);
@@ -3152,6 +3154,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
31523154
}
31533155
compiler_use_next_block(c, except);
31543156
}
3157+
compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL);
31553158
ADDOP(c, RERAISE);
31563159
compiler_use_next_block(c, orelse);
31573160
VISIT_SEQ(c, stmt, s->v.Try.orelse);

0 commit comments

Comments
 (0)