bpo-44570: Fix line tracing for forward jumps to duplicated tails (GH-27067)
diff --git a/Python/ceval.c b/Python/ceval.c
index 25548e3..2674e46 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;
}