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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,34 @@ def test_jump_across_with(output):
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed jumping out of "with" block by setting f_lineno.
24 changes: 15 additions & 9 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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) */

Expand Down Expand Up @@ -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. */
Expand Down