Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Include/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,9 @@ PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, int optimize);
#define Py_eval_input 258
#define Py_func_type_input 345

/* Compiler Return Flags */
#define CR_FALSE 0
#define CR_TRUE 1
#define CR_IGNORE 2 /* ignore do_not_return */

#endif /* !Py_COMPILE_H */
2 changes: 1 addition & 1 deletion Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ def jumpy():
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=96, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=98, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=100, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=174, argrepr='to 174', offset=102, starts_line=20, is_jump_target=True),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=174, argrepr='to 174', offset=102, starts_line=28, is_jump_target=True),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=12, argval=118, argrepr='to 118', offset=104, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=106, starts_line=21, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False),
Expand Down
30 changes: 30 additions & 0 deletions Lib/test/test_grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,16 @@ def test_break_in_finally(self):
break
self.assertEqual(count, 0)

def g1():
for count in [0, 1]:
for count in [0, 1]:
try:
return count
finally:
break
return 3
self.assertEqual(g1(), 3)

def test_continue_in_finally(self):
count = 0
while count < 2:
Expand Down Expand Up @@ -969,6 +979,15 @@ def test_continue_in_finally(self):
break
self.assertEqual(count, 1)

def g1():
for count in [0, 1]:
try:
return count
finally:
continue
return 3
self.assertEqual(g1(), 3)

def test_return_in_finally(self):
def g1():
try:
Expand All @@ -991,6 +1010,17 @@ def g3():
return 4
self.assertEqual(g3(), 4)

def g4():
for number in range(2):
try:
return 1/number
finally:
if number > 0:
return number
else:
continue
self.assertEqual(g4(), 1)

def test_yield(self):
# Allowed as standalone statement
def g(): yield 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix segfaults when continue/break inside of finally with a return inside of
try. Also optimizes bytecode by cutting pieces that never going to be
executed. (Contributed by Batuhan Taskaya)
49 changes: 34 additions & 15 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ struct compiler {
This can be used to temporarily visit
nodes without emitting bytecode to
check only errors. */
int c_do_not_return; /* The compiler won't do anything except
syntax check when it sees a return */

PyObject *c_const_cache; /* Python dict holding all constants,
including names tuple */
Expand Down Expand Up @@ -346,6 +348,7 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
c.c_optimize = (optimize == -1) ? config->optimization_level : optimize;
c.c_nestlevel = 0;
c.c_do_not_emit_bytecode = 0;
c.c_do_not_return = CR_FALSE;

if (!_PyAST_Optimize(mod, arena, c.c_optimize)) {
goto finally;
Expand Down Expand Up @@ -2780,23 +2783,24 @@ compiler_return(struct compiler *c, stmt_ty s)
return compiler_error(
c, "'return' with value in async generator");
}
if (preserve_tos) {
VISIT(c, expr, s->v.Return.value);
}
for (int depth = c->u->u_nfblocks; depth--;) {
struct fblockinfo *info = &c->u->u_fblock[depth];
if (c->c_do_not_return != CR_TRUE){
if (preserve_tos) {
VISIT(c, expr, s->v.Return.value);
}
for (int depth = c->u->u_nfblocks; depth--;) {
struct fblockinfo *info = &c->u->u_fblock[depth];

if (!compiler_unwind_fblock(c, info, preserve_tos))
return 0;
}
if (s->v.Return.value == NULL) {
ADDOP_LOAD_CONST(c, Py_None);
}
else if (!preserve_tos) {
VISIT(c, expr, s->v.Return.value);
if (!compiler_unwind_fblock(c, info, preserve_tos))
return 0;
}
if (s->v.Return.value == NULL) {
ADDOP_LOAD_CONST(c, Py_None);
}
else if (!preserve_tos) {
VISIT(c, expr, s->v.Return.value);
}
ADDOP(c, RETURN_VALUE);
}
ADDOP(c, RETURN_VALUE);

return 1;
}

Expand All @@ -2812,6 +2816,9 @@ compiler_break(struct compiler *c)
ADDOP_JABS(c, JUMP_ABSOLUTE, info->fb_exit);
return 1;
}
if (info->fb_type == FINALLY_END && c->c_do_not_return == CR_FALSE){
c->c_do_not_return = CR_TRUE;
}
}
return compiler_error(c, "'break' outside loop");
}
Expand All @@ -2826,6 +2833,9 @@ compiler_continue(struct compiler *c)
ADDOP_JABS(c, JUMP_ABSOLUTE, info->fb_block);
return 1;
}
if (info->fb_type == FINALLY_END && c->c_do_not_return == CR_FALSE){
c->c_do_not_return = CR_TRUE;
}
if (!compiler_unwind_fblock(c, info, 0))
return 0;
}
Expand Down Expand Up @@ -2876,6 +2886,13 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
if (body == NULL || end == NULL)
return 0;

if (!compiler_push_fblock(c, FINALLY_END, body, end))
return 0;
c->c_do_not_emit_bytecode = 1;
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
c->c_do_not_emit_bytecode = 0;
compiler_pop_fblock(c, FINALLY_END, body);

/* `try` block */
ADDOP_JREL(c, SETUP_FINALLY, end);
compiler_use_next_block(c, body);
Expand All @@ -2894,10 +2911,12 @@ compiler_try_finally(struct compiler *c, stmt_ty s)

/* `finally` block */
compiler_use_next_block(c, end);
c->c_do_not_return = CR_IGNORE;
if (!compiler_push_fblock(c, FINALLY_END, end, NULL))
return 0;
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
ADDOP(c, END_FINALLY);
c->c_do_not_return = CR_FALSE; /* be sure it is turned off */
compiler_pop_fblock(c, FINALLY_END, end);
return 1;
}
Expand Down
10 changes: 5 additions & 5 deletions Python/importlib.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Python/importlib_zipimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ const unsigned char _Py_M__zipimport[] = {
0,0,0,114,9,0,0,0,114,9,0,0,0,114,10,0,
0,0,218,20,95,103,101,116,95,100,101,99,111,109,112,114,
101,115,115,95,102,117,110,99,254,1,0,0,115,24,0,0,
0,0,2,4,3,10,1,8,2,4,1,4,1,16,1,14,
0,0,2,4,3,10,1,8,2,4,7,4,251,16,1,14,
1,10,1,18,2,6,2,10,1,114,144,0,0,0,99,2,
0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,9,
0,0,0,67,0,0,0,115,128,1,0,0,124,1,92,8,
Expand Down