[Python-checkins] bpo-39114: Fix tracing of except handlers with name binding (GH-17769)

Pablo Galindo webhook-mailer at python.org
Thu Jan 2 06:38:56 EST 2020


https://github.com/python/cpython/commit/04ec7a1f7a5b92187a73cd02670958444c6f2220
commit: 04ec7a1f7a5b92187a73cd02670958444c6f2220
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-01-02T11:38:44Z
summary:

bpo-39114: Fix tracing of except handlers with name binding (GH-17769)

When producing the bytecode of exception handlers with name binding (like `except Exception as e`) we need to produce a try-finally block to make sure that the name is deleted after the handler is executed to prevent cycles in the stack frame objects. The bytecode associated with this try-finally block does not have source lines associated and it was causing problems when the tracing functionality was running over it.

files:
A Misc/NEWS.d/next/Core and Builtins/2019-12-31-18-25-45.bpo-39114.WG9alt.rst
M Lib/test/test_sys_settrace.py
M Python/ceval.c

diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py
index 0af015aa56bb4..a0d1122fad83b 100644
--- a/Lib/test/test_sys_settrace.py
+++ b/Lib/test/test_sys_settrace.py
@@ -481,6 +481,51 @@ def func():
             [(0, 'call'),
              (1, 'line')])
 
+    def test_18_except_with_name(self):
+        def func():
+            try:
+                try:
+                    raise Exception
+                except Exception as e:
+                    raise
+                    x = "Something"
+                    y = "Something"
+            except Exception:
+                pass
+
+        self.run_and_compare(func,
+            [(0, 'call'),
+             (1, 'line'),
+             (2, 'line'),
+             (3, 'line'),
+             (3, 'exception'),
+             (4, 'line'),
+             (5, 'line'),
+             (8, 'line'),
+             (9, 'line'),
+             (9, 'return')])
+
+    def test_19_except_with_finally(self):
+        def func():
+            try:
+                try:
+                    raise Exception
+                finally:
+                    y = "Something"
+            except Exception:
+                b = 23
+
+        self.run_and_compare(func,
+            [(0, 'call'),
+             (1, 'line'),
+             (2, 'line'),
+             (3, 'line'),
+             (3, 'exception'),
+             (5, 'line'),
+             (6, 'line'),
+             (7, 'line'),
+             (7, 'return')])
+
 
 class SkipLineEventsTraceTestCase(TraceTestCase):
     """Repeat the trace tests, but with per-line events skipped"""
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-12-31-18-25-45.bpo-39114.WG9alt.rst b/Misc/NEWS.d/next/Core and Builtins/2019-12-31-18-25-45.bpo-39114.WG9alt.rst
new file mode 100644
index 0000000000000..d742af9d3262e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-12-31-18-25-45.bpo-39114.WG9alt.rst	
@@ -0,0 +1,2 @@
+Fix incorrent line execution reporting in trace functions when tracing
+exception handlers with name binding. Patch by Pablo Galindo.
diff --git a/Python/ceval.c b/Python/ceval.c
index 96ed329b0d995..bd9454b2812dd 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3610,7 +3610,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 PUSH(val);
                 PUSH(exc);
                 JUMPTO(handler);
-                if (_Py_TracingPossible(ceval)) {
+                if (_Py_TracingPossible(ceval) &&
+                    ((f->f_lasti < instr_lb || f->f_lasti >= instr_ub) ||
+                    !(f->f_lasti == instr_lb || f->f_lasti < instr_prev))) {
                     /* Make sure that we trace line after exception */
                     instr_prev = INT_MAX;
                 }



More information about the Python-checkins mailing list