diff --git a/Include/compile.h b/Include/compile.h index 1cda955c142551..d16b2954314026 100644 --- a/Include/compile.h +++ b/Include/compile.h @@ -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 */ diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 652af45d55ade9..214219d6bfd1f6 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -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), diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 78d94593c7f322..d38ec9f2723305 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -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: @@ -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: @@ -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 diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-08-13-09-41-55.bpo-37830.Zpn3R3.rst b/Misc/NEWS.d/next/Core and Builtins/2019-08-13-09-41-55.bpo-37830.Zpn3R3.rst new file mode 100644 index 00000000000000..ce360a6d38ff51 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-08-13-09-41-55.bpo-37830.Zpn3R3.rst @@ -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) diff --git a/Python/compile.c b/Python/compile.c index d2de7a72a811ff..81327100cd4b0d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -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 */ @@ -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; @@ -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; } @@ -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"); } @@ -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; } @@ -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); @@ -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; } diff --git a/Python/importlib.h b/Python/importlib.h index 5738af03b0543e..9ba369e9a31588 100644 --- a/Python/importlib.h +++ b/Python/importlib.h @@ -167,7 +167,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 115,101,169,2,114,30,0,0,0,114,35,0,0,0,114,10, 0,0,0,114,10,0,0,0,114,11,0,0,0,114,38,0, 0,0,78,0,0,0,115,30,0,0,0,0,6,8,1,8, - 1,2,2,8,1,20,1,6,1,14,1,18,1,8,1,12, + 16,2,243,8,1,20,1,6,1,14,1,18,1,8,1,12, 1,12,1,24,2,10,1,16,2,122,19,95,77,111,100,117, 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1, 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,9, @@ -329,7 +329,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 12,114,101,108,101,97,115,101,95,108,111,99,107,41,2,218, 3,114,101,102,114,17,0,0,0,114,10,0,0,0,114,10, 0,0,0,114,11,0,0,0,218,2,99,98,176,0,0,0, - 115,10,0,0,0,0,1,8,1,2,4,14,1,10,2,122, + 115,10,0,0,0,0,1,8,8,2,253,14,1,10,2,122, 28,95,103,101,116,95,109,111,100,117,108,101,95,108,111,99, 107,46,60,108,111,99,97,108,115,62,46,99,98,41,10,114, 57,0,0,0,114,58,0,0,0,114,59,0,0,0,218,8, @@ -338,7 +338,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 102,114,61,0,0,0,114,60,0,0,0,41,3,114,17,0, 0,0,114,24,0,0,0,114,62,0,0,0,114,10,0,0, 0,114,10,0,0,0,114,11,0,0,0,114,53,0,0,0, - 157,0,0,0,115,28,0,0,0,0,6,8,1,2,1,2, + 157,0,0,0,115,28,0,0,0,0,6,8,26,2,232,2, 1,14,1,14,1,10,2,8,1,8,1,10,2,8,2,12, 11,20,2,10,2,114,53,0,0,0,99,1,0,0,0,0, 0,0,0,0,0,0,0,2,0,0,0,8,0,0,0,67, @@ -938,7 +938,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 96,0,0,0,114,17,0,0,0,218,3,109,115,103,114,10, 0,0,0,114,10,0,0,0,114,11,0,0,0,114,93,0, 0,0,71,2,0,0,115,34,0,0,0,0,2,6,1,10, - 1,16,1,10,1,12,1,2,1,10,1,10,1,14,2,16, + 1,16,1,10,1,12,20,2,238,10,1,10,1,14,2,16, 2,14,1,12,4,14,2,16,4,14,1,24,1,114,93,0, 0,0,99,1,0,0,0,0,0,0,0,0,0,0,0,2, 0,0,0,8,0,0,0,67,0,0,0,115,26,1,0,0, @@ -1000,7 +1000,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,14, 95,108,111,97,100,95,117,110,108,111,99,107,101,100,138,2, 0,0,115,46,0,0,0,0,2,10,2,12,1,8,2,8, - 5,6,1,2,1,12,1,2,1,10,1,10,1,16,3,16, + 5,6,24,2,234,12,1,2,1,10,1,10,1,16,3,16, 1,6,1,2,1,14,1,14,1,6,1,8,5,14,1,12, 1,20,2,8,2,114,159,0,0,0,99,1,0,0,0,0, 0,0,0,0,0,0,0,1,0,0,0,10,0,0,0,67, diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h index 056e85d343d8b6..e5bf193e837f17 100644 --- a/Python/importlib_zipimport.h +++ b/Python/importlib_zipimport.h @@ -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,