From 26c9f565d016db21257a60d29ab2c99383dd5ac7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 11 Mar 2018 08:32:47 +0200 Subject: bpo-33026: Fix jumping out of "with" block by setting f_lineno. (#6026) --- Lib/test/test_sys_settrace.py | 28 ++++++++++++++++++++++ .../2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst | 1 + Objects/frameobject.c | 24 ++++++++++++------- 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 7df10cb..72cce33 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -827,6 +827,34 @@ class JumpTestCase(unittest.TestCase): with tracecontext(output, 4): output.append(5) + @jump_test(4, 5, [1, 3, 5, 6]) + def test_jump_out_of_with_block_within_for_block(output): + output.append(1) + for i in [1]: + with tracecontext(output, 3): + output.append(4) + output.append(5) + output.append(6) + + @jump_test(4, 5, [1, 2, 3, 5, -2, 6]) + def test_jump_out_of_with_block_within_with_block(output): + output.append(1) + with tracecontext(output, 2): + with tracecontext(output, 3): + output.append(4) + output.append(5) + output.append(6) + + @jump_test(5, 6, [2, 4, 6, 7]) + def test_jump_out_of_with_block_within_finally_block(output): + try: + output.append(2) + finally: + with tracecontext(output, 4): + output.append(5) + output.append(6) + output.append(7) + @jump_test(8, 11, [1, 3, 5, 11, 12]) def test_jump_out_of_complex_nested_blocks(output): output.append(1) diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst b/Misc/NEWS.d/next/Core and Builtins/2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst new file mode 100644 index 0000000..dc166d1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst @@ -0,0 +1 @@ +Fixed jumping out of "with" block by setting f_lineno. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index b9f380d..31ad8d0 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -89,7 +89,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) long l_new_lineno; int overflow; int new_lasti = 0; /* The new value of f_lasti */ - int new_iblock = 0; /* The new value of f_iblock */ unsigned char *code = NULL; /* The bytecode for the frame... */ Py_ssize_t code_len = 0; /* ...and its length */ unsigned char *lnotab = NULL; /* Iterating over co_lnotab */ @@ -99,6 +98,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) int addr = 0; /* (ditto) */ int delta_iblock = 0; /* Scanning the SETUPs and POPs */ int for_loop_delta = 0; /* (ditto) */ + int delta; int blockstack[CO_MAXBLOCKS]; /* Walking the 'finally' blocks */ int blockstack_top = 0; /* (ditto) */ @@ -258,19 +258,25 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) assert(blockstack_top == 0); /* Pop any blocks that we're jumping out of. */ - new_iblock = f->f_iblock - delta_iblock; - while (f->f_iblock > new_iblock) { - PyTryBlock *b = &f->f_blockstack[--f->f_iblock]; - while ((f->f_stacktop - f->f_valuestack) > b->b_level) { - PyObject *v = (*--f->f_stacktop); - Py_DECREF(v); + delta = 0; + if (delta_iblock > 0) { + f->f_iblock -= delta_iblock; + PyTryBlock *b = &f->f_blockstack[f->f_iblock]; + delta = (f->f_stacktop - f->f_valuestack) - b->b_level; + if (b->b_type == SETUP_FINALLY && + code[b->b_handler] == WITH_CLEANUP_START) + { + /* Pop the exit function. */ + delta++; } } /* Pop the iterators of any 'for' loop we're jumping out of. */ - while (for_loop_delta > 0) { + delta += for_loop_delta; + + while (delta > 0) { PyObject *v = (*--f->f_stacktop); Py_DECREF(v); - for_loop_delta--; + delta--; } /* Finally set the new f_lineno and f_lasti and return OK. */ -- cgit v0.12