Skip to content

Commit 48a9c0e

Browse files
authored
[3.9] bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395) (GH-23303)
* bpo-39934: backport PR 22395 to 3.9
1 parent 05a5d69 commit 48a9c0e

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
@@ -946,6 +946,15 @@ def test_empty_line_after_linecont(self):
946946
except SyntaxError:
947947
self.fail("Empty line after a line continuation character is valid.")
948948

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

950959
def test_barry_as_flufl_with_syntax_errors(self):
951960
# The "barry_as_flufl" rule can produce some "bugs-at-a-distance" if
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
@@ -84,8 +84,8 @@ It's called a frame block to distinguish it from a basic block in the
8484
compiler IR.
8585
*/
8686

87-
enum fblocktype { WHILE_LOOP, FOR_LOOP, EXCEPT, FINALLY_TRY, FINALLY_END,
88-
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE };
87+
enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
88+
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER };
8989

9090
struct fblockinfo {
9191
enum fblocktype fb_type;
@@ -1624,9 +1624,7 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
16241624
{
16251625
struct fblockinfo *f;
16261626
if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
1627-
PyErr_SetString(PyExc_SyntaxError,
1628-
"too many statically nested blocks");
1629-
return 0;
1627+
return compiler_error(c, "too many statically nested blocks");
16301628
}
16311629
f = &c->u->u_fblock[c->u->u_nfblocks++];
16321630
f->fb_type = t;
@@ -1666,6 +1664,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
16661664
{
16671665
switch (info->fb_type) {
16681666
case WHILE_LOOP:
1667+
case EXCEPTION_HANDLER:
16691668
return 1;
16701669

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

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

@@ -3064,14 +3063,17 @@ compiler_try_except(struct compiler *c, stmt_ty s)
30643063
return 0;
30653064
ADDOP_JREL(c, SETUP_FINALLY, except);
30663065
compiler_use_next_block(c, body);
3067-
if (!compiler_push_fblock(c, EXCEPT, body, NULL, NULL))
3066+
if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL))
30683067
return 0;
30693068
VISIT_SEQ(c, stmt, s->v.Try.body);
30703069
ADDOP(c, POP_BLOCK);
3071-
compiler_pop_fblock(c, EXCEPT, body);
3070+
compiler_pop_fblock(c, TRY_EXCEPT, body);
30723071
ADDOP_JREL(c, JUMP_FORWARD, orelse);
30733072
n = asdl_seq_LEN(s->v.Try.handlers);
30743073
compiler_use_next_block(c, except);
3074+
/* Runtime will push a block here, so we need to account for that */
3075+
if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL))
3076+
return 0;
30753077
for (i = 0; i < n; i++) {
30763078
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
30773079
s->v.Try.handlers, i);
@@ -3156,6 +3158,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
31563158
}
31573159
compiler_use_next_block(c, except);
31583160
}
3161+
compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL);
31593162
ADDOP(c, RERAISE);
31603163
compiler_use_next_block(c, orelse);
31613164
VISIT_SEQ(c, stmt, s->v.Try.orelse);

0 commit comments

Comments
 (0)