mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
bpo-44570: Fix line tracing for forward jumps to duplicated tails (GH-27067)
This commit is contained in:
parent
61eb9b5dfd
commit
9f2c63b258
3 changed files with 50 additions and 21 deletions
|
@ -1316,8 +1316,8 @@ def test_pdb_issue_20766():
|
|||
-> print('pdb %d: %s' % (i, sess._previous_sigint_handler))
|
||||
(Pdb) continue
|
||||
pdb 1: <built-in function default_int_handler>
|
||||
> <doctest test.test_pdb.test_pdb_issue_20766[0]>(5)test_function()
|
||||
-> sess.set_trace(sys._getframe())
|
||||
> <doctest test.test_pdb.test_pdb_issue_20766[0]>(6)test_function()
|
||||
-> print('pdb %d: %s' % (i, sess._previous_sigint_handler))
|
||||
(Pdb) continue
|
||||
pdb 2: <built-in function default_int_handler>
|
||||
"""
|
||||
|
|
|
@ -1041,6 +1041,41 @@ class TraceTestCase(unittest.TestCase):
|
|||
(-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"""
|
||||
|
|
|
@ -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 @@ main_loop:
|
|||
}
|
||||
|
||||
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 @@ main_loop:
|
|||
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 @@ main_loop:
|
|||
}
|
||||
NEXTOPARG();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LLTRACE
|
||||
/* Instruction tracing */
|
||||
|
@ -4502,9 +4504,6 @@ exception_unwind:
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue