Author: Armin Rigo <ar...@tunes.org>
Branch: py3.5
Changeset: r88479:038ed5ec2571
Date: 2016-11-19 17:39 +0100
http://bitbucket.org/pypy/pypy/changeset/038ed5ec2571/

Log:    Test and fix for setting f_lineno

diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -647,51 +647,43 @@
             raise oefmt(space.w_ValueError,
                         "can't jump to 'except' line as there's no exception")
 
-        # Don't jump into or out of a finally block.
-        # Unlike CPython, we can't jump into or out of an except block
-        # either---there would be a mess with SysExcInfoRestorer.
+        # Don't jump inside or out of an except or a finally block.
+        # Note that CPython doesn't check except blocks,
+        # but that results in crashes (tested on 3.5.2+).
         f_lasti_handler_addr = -1
         new_lasti_handler_addr = -1
-        blockstack = [-1]    # list of odd length:
-                             #   * addr of most recent outermost handler
-                             # [ * addr of start of outermost block
-                             #   * addr of most recent handler in that block 
-                             #       (last two items repeated) ]
+        blockstack = []     # current blockstack (addresses of SETUP_*)
+        endblock = [-1]     # current finally/except block stack
         addr = 0
         while addr < len(code):
             op = ord(code[addr])
             if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH,
                       SETUP_ASYNC_WITH):
                 blockstack.append(addr)
-                blockstack.append(-1)
             elif op == POP_BLOCK:
-                if len(blockstack) < 3:
+                if len(blockstack) == 0:
                     raise oefmt(space.w_SystemError,
-                                "blocks not properly nested in this bytecode")
-                blockstack.pop()
+                           "POP_BLOCK not properly nested in this bytecode")
                 setup_op = ord(code[blockstack.pop()])
                 if setup_op != SETUP_LOOP:
-                    blockstack[-1] = addr
-            elif op == END_FINALLY:    # "async for" nests blocks
-                blockstack[-1] = -1    # strangely, careful here
+                    endblock.append(addr)
+            elif op == END_FINALLY:
+                if len(endblock) <= 1:
+                    raise oefmt(space.w_SystemError,
+                           "END_FINALLY not properly nested in this bytecode")
+                endblock.pop()
 
-            if addr == new_lasti or addr == self.last_instr:
-                ii = len(blockstack) - 1
-                while ii > 0 and blockstack[ii] == -1:
-                    ii -= 2
-                assert ii >= 0
-                handler_addr = blockstack[ii]
-                if addr == new_lasti:
-                    new_lasti_handler_addr = handler_addr
-                if addr == self.last_instr:
-                    f_lasti_handler_addr = handler_addr
+            if addr == new_lasti:
+                new_lasti_handler_addr = endblock[-1]
+            if addr == self.last_instr:
+                f_lasti_handler_addr = endblock[-1]
 
             if op >= HAVE_ARGUMENT:
                 addr += 3
             else:
                 addr += 1
 
-        if len(blockstack) != 1:
+        if len(blockstack) != 0 or len(endblock) != 1:
             raise oefmt(space.w_SystemError,
                         "blocks not properly nested in this bytecode")
 
diff --git a/pypy/interpreter/test/test_pyframe.py 
b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -121,6 +121,30 @@
         assert str(errors[0]).startswith(
             "can't jump into or out of an 'expect' or 'finally' block")
 
+    def test_f_lineno_set_3(self):
+        def jump_in_nested_finally(output):
+            try:
+                output.append(2)
+            finally:
+                output.append(4)
+                try:
+                    output.append(6)
+                finally:
+                    output.append(8)
+                output.append(9)
+        output = []
+
+        def tracer(f, event, *args):
+            if event == 'line' and len(output) == 1:
+                f.f_lineno += 5
+            return tracer
+
+        import sys
+        sys.settrace(tracer)
+        jump_in_nested_finally(output)
+        sys.settrace(None)
+        assert output == [2, 9]
+
     def test_f_lineno_set_firstline(self):
         r"""
         seen = []
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to