From c14641d5a075a0adeff5de36c54694c4578df46f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 4 Jun 2017 12:36:47 +0300 Subject: [PATCH] bpo-24340: Fixed a "leak" in the computation of the stack size effect for try/except and try/finally. --- Lib/test/test_compile.py | 13 +++++++++++++ Misc/NEWS | 3 +++ Python/compile.c | 15 ++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index b4a52a53105eda1..8a2c5a4a13f1ea9 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -708,6 +708,19 @@ def test_func_and(self): code += " x and x\n" * self.N self.check_stack_size(code) + def test_try_except(self): + # See issue #24340. + source = "try: x\nexcept E: y\n" + code = compile(source, "", "exec") + code2 = compile(source * self.N, "", "exec") + self.assertEqual(code2.co_stacksize, code.co_stacksize) + + def test_try_finally(self): + source = "try: x\nfinally: y\n" + code = compile(source, "", "exec") + code2 = compile(source * self.N, "", "exec") + self.assertEqual(code2.co_stacksize, code.co_stacksize) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index e6e8f95f4653bad..cdcaddf28464bfe 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-24340: Fixed a "leak" in the computation of the stack size effect for + try/except and try/finally. + - bpo-25324: Tokens needed for parsing in Python moved to C. ``COMMENT``, ``NL`` and ``ENCODING``. This way the tokens and tok_names in the token module don't get changed when you import the tokenize module. diff --git a/Python/compile.c b/Python/compile.c index dad7404a85f3f4f..f176ebd455a074e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -946,9 +946,9 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) case POP_BLOCK: return 0; case POP_EXCEPT: - return 0; /* -3 except if bad bytecode */ + return -3; /* the previous exception state */ case END_FINALLY: - return -1; /* or -2 or -3 if exception occurred */ + return -6; /* see SETUP_FINALLY */ case STORE_NAME: return -1; @@ -4850,11 +4850,12 @@ stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth) if (instr->i_opcode == FOR_ITER) { target_depth = depth-2; } - else if (instr->i_opcode == SETUP_FINALLY || - instr->i_opcode == SETUP_EXCEPT) { - target_depth = depth+3; - if (target_depth > maxdepth) - maxdepth = target_depth; + else if (instr->i_opcode == SETUP_EXCEPT) { + depth = depth - 6; + } + else if (instr->i_opcode == SETUP_FINALLY) { + depth = depth - 1; /* for None */ + continue; /* should pass to finally handler in any case */ } else if (instr->i_opcode == JUMP_IF_TRUE_OR_POP || instr->i_opcode == JUMP_IF_FALSE_OR_POP)