From 71a08e902a9f1605ce8ea92ae0de5f8f9a68df15 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 8 Jul 2021 13:54:44 +0100 Subject: [PATCH] Handle forward jumps where the target has the same line number as the physically preceding instruction. --- Lib/test/test_pdb.py | 4 ++-- Lib/test/test_sys_settrace.py | 35 +++++++++++++++++++++++++++++++++++ Python/ceval.c | 32 +++++++++++++------------------- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index cdd427a570e9fa..63afb81cb168ff 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1316,8 +1316,8 @@ def test_pdb_issue_20766(): -> print('pdb %d: %s' % (i, sess._previous_sigint_handler)) (Pdb) continue pdb 1: - > (5)test_function() - -> sess.set_trace(sys._getframe()) + > (6)test_function() + -> print('pdb %d: %s' % (i, sess._previous_sigint_handler)) (Pdb) continue pdb 2: """ diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 0174f80dce603a..09d0adca2ee7a1 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1041,6 +1041,41 @@ def func_return(): (-8, 'return'), (1, 'return')]) + def test_flow_converges_on_same_line(self): + + def foo(x): + if x: + try: + 1/(x - 1) + except ZeroDivisionError: + pass + return x + + def func(): + for i in range(2): + foo(i) + + self.run_and_compare(func, + [(0, 'call'), + (1, 'line'), + (2, 'line'), + (-8, 'call'), + (-7, 'line'), + (-2, 'line'), + (-2, 'return'), + (1, 'line'), + (2, 'line'), + (-8, 'call'), + (-7, 'line'), + (-6, 'line'), + (-5, 'line'), + (-5, 'exception'), + (-4, 'line'), + (-3, 'line'), + (-2, 'line'), + (-2, 'return'), + (1, 'line'), + (1, 'return')]) class SkipLineEventsTraceTestCase(TraceTestCase): """Repeat the trace tests, but with per-line events skipped""" diff --git a/Python/ceval.c b/Python/ceval.c index 25548e34db246b..2674e46b3d6065 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -35,7 +35,6 @@ typedef struct { PyCodeObject *code; // The code object for the bounds. May be NULL. - int instr_prev; // Only valid if code != NULL. PyCodeAddressRange bounds; // Only valid if code != NULL. CFrame cframe; } PyTraceInfo; @@ -78,8 +77,8 @@ static void call_exc_trace(Py_tracefunc, PyObject *, PyTraceInfo *trace_info); static int maybe_call_line_trace(Py_tracefunc, PyObject *, PyThreadState *, PyFrameObject *, - PyTraceInfo *); -static void maybe_dtrace_line(PyFrameObject *, PyTraceInfo *); + PyTraceInfo *, int); +static void maybe_dtrace_line(PyFrameObject *, PyTraceInfo *, int); static void dtrace_function_entry(PyFrameObject *); static void dtrace_function_return(PyFrameObject *); @@ -1781,11 +1780,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } tracing_dispatch: + { + int instr_prev = f->f_lasti; f->f_lasti = INSTR_OFFSET(); NEXTOPARG(); if (PyDTrace_LINE_ENABLED()) - maybe_dtrace_line(f, &trace_info); + maybe_dtrace_line(f, &trace_info, instr_prev); /* line-by-line tracing support */ @@ -1799,7 +1800,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) err = maybe_call_line_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f, - &trace_info); + &trace_info, instr_prev); /* Reload possibly changed frame fields */ JUMPTO(f->f_lasti); stack_pointer = f->f_valuestack+f->f_stackdepth; @@ -1810,6 +1811,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } NEXTOPARG(); } + } #ifdef LLTRACE /* Instruction tracing */ @@ -4502,9 +4504,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PUSH(val); PUSH(exc); JUMPTO(handler); - if (trace_info.cframe.use_tracing) { - trace_info.instr_prev = INT_MAX; - } /* Resume normal execution */ f->f_state = FRAME_EXECUTING; goto main_loop; @@ -5455,7 +5454,6 @@ initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame) { if (trace_info->code != frame->f_code) { trace_info->code = frame->f_code; - trace_info->instr_prev = -1; _PyCode_InitAddressRange(frame->f_code, &trace_info->bounds); } } @@ -5507,7 +5505,7 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) static int maybe_call_line_trace(Py_tracefunc func, PyObject *obj, PyThreadState *tstate, PyFrameObject *frame, - PyTraceInfo *trace_info) + PyTraceInfo *trace_info, int instr_prev) { int result = 0; @@ -5516,13 +5514,11 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, then call the trace function if we're tracing source lines. */ initialize_trace_info(trace_info, frame); - int lastline = trace_info->bounds.ar_line; + int lastline = _PyCode_CheckLineNumber(instr_prev*2, &trace_info->bounds); int line = _PyCode_CheckLineNumber(frame->f_lasti*2, &trace_info->bounds); if (line != -1 && frame->f_trace_lines) { - /* Trace backward edges or first instruction of a new line */ - if (frame->f_lasti < trace_info->instr_prev || - (line != lastline && frame->f_lasti*2 == trace_info->bounds.ar_start)) - { + /* Trace backward edges or if line number has changed */ + if (frame->f_lasti < instr_prev || line != lastline) { result = call_trace(func, obj, tstate, frame, trace_info, PyTrace_LINE, Py_None); } } @@ -5530,7 +5526,6 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, if (frame->f_trace_opcodes) { result = call_trace(func, obj, tstate, frame, trace_info, PyTrace_OPCODE, Py_None); } - trace_info->instr_prev = frame->f_lasti; return result; } @@ -6475,7 +6470,7 @@ dtrace_function_return(PyFrameObject *f) /* DTrace equivalent of maybe_call_line_trace. */ static void maybe_dtrace_line(PyFrameObject *frame, - PyTraceInfo *trace_info) + PyTraceInfo *trace_info, int instr_prev) { const char *co_filename, *co_name; @@ -6487,7 +6482,7 @@ maybe_dtrace_line(PyFrameObject *frame, /* If the last instruction falls at the start of a line or if it represents a jump backwards, update the frame's line number and call the trace function. */ - if (line != frame->f_lineno || frame->f_lasti < trace_info->instr_prev) { + if (line != frame->f_lineno || frame->f_lasti < instr_prev) { if (line != -1) { frame->f_lineno = line; co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); @@ -6499,7 +6494,6 @@ maybe_dtrace_line(PyFrameObject *frame, PyDTrace_LINE(co_filename, co_name, line); } } - trace_info->instr_prev = frame->f_lasti; }