]> granicus.if.org Git - python/commitdiff
bpo-33026: Fix jumping out of "with" block by setting f_lineno. (#6026)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 11 Mar 2018 06:32:47 +0000 (08:32 +0200)
committerGitHub <noreply@github.com>
Sun, 11 Mar 2018 06:32:47 +0000 (08:32 +0200)
Lib/test/test_sys_settrace.py
Misc/NEWS.d/next/Core and Builtins/2018-03-08-09-48-38.bpo-33026.QZA3Ba.rst [new file with mode: 0644]
Objects/frameobject.c

index 7df10cb5c1f7516f04bc40fcac69b7b4138d14a9..72cce33392dc14113aa3db3126dcf29731004125 100644 (file)
@@ -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 (file)
index 0000000..dc166d1
--- /dev/null
@@ -0,0 +1 @@
+Fixed jumping out of "with" block by setting f_lineno.
index b9f380d7b60dec454751da92dd98a23198be565d..31ad8d0be226cee60a9e2c52c4fcd15bf608296c 100644 (file)
@@ -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. */