From 397466dfd905b5132f1c831cd9dff3ecc40b3218 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 23 Mar 2018 14:46:45 +0200 Subject: [PATCH] bpo-30953: Improve error messages and add tests for jumping (GH-6196) into/out of an except block. --- Lib/test/test_sys_settrace.py | 78 ++++++++++++++++++++++++++++++----- Objects/frameobject.c | 8 +++- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 1fa43b29ec9..f5125a45051 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1201,8 +1201,16 @@ class JumpTestCase(unittest.TestCase): output.append(7) output.append(8) - @jump_test(3, 6, [2, 5, 6], (ValueError, 'finally')) + @jump_test(1, 5, [], (ValueError, "into a 'finally'")) def test_no_jump_into_finally_block(output): + output.append(1) + try: + output.append(3) + finally: + output.append(5) + + @jump_test(3, 6, [2, 5, 6], (ValueError, "into a 'finally'")) + def test_no_jump_into_finally_block_from_try_block(output): try: output.append(2) output.append(3) @@ -1211,15 +1219,7 @@ class JumpTestCase(unittest.TestCase): output.append(6) output.append(7) - @jump_test(1, 5, [], (ValueError, 'finally')) - def test_no_jump_into_finally_block_2(output): - output.append(1) - try: - output.append(3) - finally: - output.append(5) - - @jump_test(5, 1, [1, 3], (ValueError, 'finally')) + @jump_test(5, 1, [1, 3], (ValueError, "out of a 'finally'")) def test_no_jump_out_of_finally_block(output): output.append(1) try: @@ -1227,6 +1227,64 @@ class JumpTestCase(unittest.TestCase): finally: output.append(5) + @jump_test(1, 5, [], (ValueError, "into an 'except'")) + def test_no_jump_into_bare_except_block(output): + output.append(1) + try: + output.append(3) + except: + output.append(5) + + @jump_test(1, 5, [], (ValueError, "into an 'except'")) + def test_no_jump_into_qualified_except_block(output): + output.append(1) + try: + output.append(3) + except Exception: + output.append(5) + + @jump_test(3, 6, [2, 5, 6], (ValueError, "into an 'except'")) + def test_no_jump_into_bare_except_block_from_try_block(output): + try: + output.append(2) + output.append(3) + except: # executed if the jump is failed + output.append(5) + output.append(6) + raise + output.append(8) + + @jump_test(3, 6, [2], (ValueError, "into an 'except'")) + def test_no_jump_into_qualified_except_block_from_try_block(output): + try: + output.append(2) + output.append(3) + except ZeroDivisionError: + output.append(5) + output.append(6) + raise + output.append(8) + + @jump_test(7, 1, [1, 3, 6], (ValueError, "out of an 'except'")) + def test_no_jump_out_of_bare_except_block(output): + output.append(1) + try: + output.append(3) + 1/0 + except: + output.append(6) + output.append(7) + + @jump_test(7, 1, [1, 3, 6], (ValueError, "out of an 'except'")) + def test_no_jump_out_of_qualified_except_block(output): + output.append(1) + try: + output.append(3) + 1/0 + except Exception: + output.append(6) + output.append(7) + @jump_test(3, 5, [1, 2, -2], (ValueError, 'into')) def test_no_jump_between_with_blocks(output): output.append(1) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 9d37935c2f7..864a8f977ea 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -277,8 +277,12 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) int first_in = target_addr <= f->f_lasti && f->f_lasti <= addr; int second_in = target_addr <= new_lasti && new_lasti <= addr; if (first_in != second_in) { - PyErr_SetString(PyExc_ValueError, - "can't jump into or out of a 'finally' block"); + op = code[target_addr]; + PyErr_Format(PyExc_ValueError, + "can't jump %s %s block", + second_in ? "into" : "out of", + (op == DUP_TOP || op == POP_TOP) ? + "an 'except'" : "a 'finally'"); return -1; } break;