[pypy-commit] pypy default: Oops, bug: if a throw() propagates the error sent in, then the 'return'

arigo pypy.commits at gmail.com
Fri Sep 16 10:49:42 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r87141:47fa78e23bfb
Date: 2016-09-16 16:49 +0200
http://bitbucket.org/pypy/pypy/changeset/47fa78e23bfb/

Log:	Oops, bug: if a throw() propagates the error sent in, then the
	'return' trace was not called. This can confuse debuggers/profilers.

diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -276,18 +276,17 @@
                 if next_instr != 0:
                     self.pushvalue(w_inputvalue)
             #
-            try:
-                w_exitvalue = self.dispatch(self.pycode, next_instr,
-                                            executioncontext)
-            except Exception:
-                executioncontext.return_trace(self, self.space.w_None)
-                raise
+            w_exitvalue = self.dispatch(self.pycode, next_instr,
+                                        executioncontext)
             executioncontext.return_trace(self, w_exitvalue)
             # it used to say self.last_exception = None
             # this is now done by the code in pypyjit module
             # since we don't want to invalidate the virtualizable
             # for no good reason
             got_exception = False
+        except Exception:
+            executioncontext.return_trace(self, self.space.w_None)
+            raise
         finally:
             executioncontext.leave(self, w_exitvalue, got_exception)
         return w_exitvalue
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
@@ -562,3 +562,21 @@
         res = f(10).g()
         sys.settrace(None)
         assert res == 10
+
+    def test_throw_trace_bug(self):
+        import sys
+        def f():
+            yield 5
+        gen = f()
+        assert next(gen) == 5
+        seen = []
+        def trace_func(frame, event, *args):
+            seen.append(event)
+            return trace_func
+        sys.settrace(trace_func)
+        try:
+            gen.throw(ValueError)
+        except ValueError:
+            pass
+        sys.settrace(None)
+        assert seen == ['call', 'exception', 'return']


More information about the pypy-commit mailing list