bpo-39934: Account for control blocks in 'except' in compiler. (GH-22395)
* Account for control blocks in 'except' in compiler. Fixes #39934.
This commit is contained in:
parent
05cc881cbc
commit
02d126aa09
|
@ -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)
|
||||
|
|
|
@ -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.
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue