Skip to content

Commit 8643345

Browse files
authored
Update frame.f_lineno before any call to the (C) tracing function. (GH-24150)
* Minimizes breakage of C extensions and ensures PyFrame_GetLineNumber is efficient.
1 parent 5c30145 commit 8643345

File tree

1 file changed

+54
-33
lines changed

1 file changed

+54
-33
lines changed

Python/ceval.c

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ _Py_IDENTIFIER(__name__);
4646

4747
/* Forward declarations */
4848
Py_LOCAL_INLINE(PyObject *) call_function(
49-
PyThreadState *tstate, PyObject ***pp_stack,
49+
PyThreadState *tstate, PyCodeAddressRange *, PyObject ***pp_stack,
5050
Py_ssize_t oparg, PyObject *kwnames);
5151
static PyObject * do_call_core(
52-
PyThreadState *tstate, PyObject *func,
52+
PyThreadState *tstate, PyCodeAddressRange *, PyObject *func,
5353
PyObject *callargs, PyObject *kwdict);
5454

5555
#ifdef LLTRACE
@@ -58,12 +58,15 @@ static int prtrace(PyThreadState *, PyObject *, const char *);
5858
#endif
5959
static int call_trace(Py_tracefunc, PyObject *,
6060
PyThreadState *, PyFrameObject *,
61+
PyCodeAddressRange *,
6162
int, PyObject *);
6263
static int call_trace_protected(Py_tracefunc, PyObject *,
6364
PyThreadState *, PyFrameObject *,
65+
PyCodeAddressRange *,
6466
int, PyObject *);
6567
static void call_exc_trace(Py_tracefunc, PyObject *,
66-
PyThreadState *, PyFrameObject *);
68+
PyThreadState *, PyFrameObject *,
69+
PyCodeAddressRange *);
6770
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
6871
PyThreadState *, PyFrameObject *,
6972
PyCodeAddressRange *, int *);
@@ -1380,6 +1383,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13801383
}
13811384

13821385
tstate->frame = f;
1386+
co = f->f_code;
1387+
PyCodeAddressRange bounds;
1388+
_PyCode_InitAddressRange(co, &bounds);
13831389

13841390
if (tstate->use_tracing) {
13851391
if (tstate->c_tracefunc != NULL) {
@@ -1398,7 +1404,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13981404
whenever an exception is detected. */
13991405
if (call_trace_protected(tstate->c_tracefunc,
14001406
tstate->c_traceobj,
1401-
tstate, f, PyTrace_CALL, Py_None)) {
1407+
tstate, f, &bounds,
1408+
PyTrace_CALL, Py_None)) {
14021409
/* Trace function raised an error */
14031410
goto exit_eval_frame;
14041411
}
@@ -1408,7 +1415,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
14081415
return itself and isn't called for "line" events */
14091416
if (call_trace_protected(tstate->c_profilefunc,
14101417
tstate->c_profileobj,
1411-
tstate, f, PyTrace_CALL, Py_None)) {
1418+
tstate, f, &bounds,
1419+
PyTrace_CALL, Py_None)) {
14121420
/* Profile function raised an error */
14131421
goto exit_eval_frame;
14141422
}
@@ -1418,9 +1426,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
14181426
if (PyDTrace_FUNCTION_ENTRY_ENABLED())
14191427
dtrace_function_entry(f);
14201428

1421-
co = f->f_code;
1422-
PyCodeAddressRange bounds;
1423-
_PyCode_InitAddressRange(co, &bounds);
14241429
int instr_prev = -1;
14251430

14261431
names = co->co_names;
@@ -2348,7 +2353,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
23482353
if (retval == NULL) {
23492354
if (tstate->c_tracefunc != NULL
23502355
&& _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
2351-
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
2356+
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f, &bounds);
23522357
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
23532358
gen_status = PYGEN_RETURN;
23542359
}
@@ -3596,7 +3601,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
35963601
goto error;
35973602
}
35983603
else if (tstate->c_tracefunc != NULL) {
3599-
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
3604+
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f, &bounds);
36003605
}
36013606
_PyErr_Clear(tstate);
36023607
}
@@ -3764,7 +3769,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37643769
`callable` will be POPed by call_function.
37653770
NULL will will be POPed manually later.
37663771
*/
3767-
res = call_function(tstate, &sp, oparg, NULL);
3772+
res = call_function(tstate, &bounds, &sp, oparg, NULL);
37683773
stack_pointer = sp;
37693774
(void)POP(); /* POP the NULL. */
37703775
}
@@ -3781,7 +3786,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37813786
We'll be passing `oparg + 1` to call_function, to
37823787
make it accept the `self` as a first argument.
37833788
*/
3784-
res = call_function(tstate, &sp, oparg + 1, NULL);
3789+
res = call_function(tstate, &bounds, &sp, oparg + 1, NULL);
37853790
stack_pointer = sp;
37863791
}
37873792

@@ -3795,7 +3800,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37953800
PREDICTED(CALL_FUNCTION);
37963801
PyObject **sp, *res;
37973802
sp = stack_pointer;
3798-
res = call_function(tstate, &sp, oparg, NULL);
3803+
res = call_function(tstate, &bounds, &sp, oparg, NULL);
37993804
stack_pointer = sp;
38003805
PUSH(res);
38013806
if (res == NULL) {
@@ -3812,7 +3817,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
38123817
assert(PyTuple_GET_SIZE(names) <= oparg);
38133818
/* We assume without checking that names contains only strings */
38143819
sp = stack_pointer;
3815-
res = call_function(tstate, &sp, oparg, names);
3820+
res = call_function(tstate, &bounds, &sp, oparg, names);
38163821
stack_pointer = sp;
38173822
PUSH(res);
38183823
Py_DECREF(names);
@@ -3857,7 +3862,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
38573862
}
38583863
assert(PyTuple_CheckExact(callargs));
38593864

3860-
result = do_call_core(tstate, func, callargs, kwargs);
3865+
result = do_call_core(tstate, &bounds, func, callargs, kwargs);
38613866
Py_DECREF(func);
38623867
Py_DECREF(callargs);
38633868
Py_XDECREF(kwargs);
@@ -4024,7 +4029,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
40244029
assert(f->f_state == FRAME_EXECUTING);
40254030
f->f_state = FRAME_UNWINDING;
40264031
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj,
4027-
tstate, f);
4032+
tstate, f, &bounds);
40284033
}
40294034
exception_unwind:
40304035
f->f_state = FRAME_UNWINDING;
@@ -4102,13 +4107,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
41024107
if (tstate->use_tracing) {
41034108
if (tstate->c_tracefunc) {
41044109
if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,
4105-
tstate, f, PyTrace_RETURN, retval)) {
4110+
tstate, f, &bounds, PyTrace_RETURN, retval)) {
41064111
Py_CLEAR(retval);
41074112
}
41084113
}
41094114
if (tstate->c_profilefunc) {
41104115
if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj,
4111-
tstate, f, PyTrace_RETURN, retval)) {
4116+
tstate, f, &bounds, PyTrace_RETURN, retval)) {
41124117
Py_CLEAR(retval);
41134118
}
41144119
}
@@ -4902,7 +4907,9 @@ prtrace(PyThreadState *tstate, PyObject *v, const char *str)
49024907

49034908
static void
49044909
call_exc_trace(Py_tracefunc func, PyObject *self,
4905-
PyThreadState *tstate, PyFrameObject *f)
4910+
PyThreadState *tstate,
4911+
PyFrameObject *f,
4912+
PyCodeAddressRange *bounds)
49064913
{
49074914
PyObject *type, *value, *traceback, *orig_traceback, *arg;
49084915
int err;
@@ -4918,7 +4925,7 @@ call_exc_trace(Py_tracefunc func, PyObject *self,
49184925
_PyErr_Restore(tstate, type, value, orig_traceback);
49194926
return;
49204927
}
4921-
err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg);
4928+
err = call_trace(func, self, tstate, f, bounds, PyTrace_EXCEPTION, arg);
49224929
Py_DECREF(arg);
49234930
if (err == 0) {
49244931
_PyErr_Restore(tstate, type, value, orig_traceback);
@@ -4933,12 +4940,13 @@ call_exc_trace(Py_tracefunc func, PyObject *self,
49334940
static int
49344941
call_trace_protected(Py_tracefunc func, PyObject *obj,
49354942
PyThreadState *tstate, PyFrameObject *frame,
4943+
PyCodeAddressRange *bounds,
49364944
int what, PyObject *arg)
49374945
{
49384946
PyObject *type, *value, *traceback;
49394947
int err;
49404948
_PyErr_Fetch(tstate, &type, &value, &traceback);
4941-
err = call_trace(func, obj, tstate, frame, what, arg);
4949+
err = call_trace(func, obj, tstate, frame, bounds, what, arg);
49424950
if (err == 0)
49434951
{
49444952
_PyErr_Restore(tstate, type, value, traceback);
@@ -4955,14 +4963,22 @@ call_trace_protected(Py_tracefunc func, PyObject *obj,
49554963
static int
49564964
call_trace(Py_tracefunc func, PyObject *obj,
49574965
PyThreadState *tstate, PyFrameObject *frame,
4966+
PyCodeAddressRange *bounds,
49584967
int what, PyObject *arg)
49594968
{
49604969
int result;
49614970
if (tstate->tracing)
49624971
return 0;
49634972
tstate->tracing++;
49644973
tstate->use_tracing = 0;
4974+
if (frame->f_lasti < 0) {
4975+
frame->f_lineno = frame->f_code->co_firstlineno;
4976+
}
4977+
else {
4978+
frame->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti, bounds);
4979+
}
49654980
result = func(obj, frame, what, arg);
4981+
frame->f_lineno = 0;
49664982
tstate->use_tracing = ((tstate->c_tracefunc != NULL)
49674983
|| (tstate->c_profilefunc != NULL));
49684984
tstate->tracing--;
@@ -5005,16 +5021,12 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
50055021
if (frame->f_lasti < *instr_prev ||
50065022
(line != lastline && frame->f_lasti == bounds->ar_start))
50075023
{
5008-
frame->f_lineno = line;
5009-
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
5010-
frame->f_lineno = 0;
5024+
result = call_trace(func, obj, tstate, frame, bounds, PyTrace_LINE, Py_None);
50115025
}
50125026
}
50135027
/* Always emit an opcode event if we're tracing all opcodes. */
50145028
if (frame->f_trace_opcodes) {
5015-
frame->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti, bounds);
5016-
result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None);
5017-
frame->f_lineno = 0;
5029+
result = call_trace(func, obj, tstate, frame, bounds, PyTrace_OPCODE, Py_None);
50185030
}
50195031
*instr_prev = frame->f_lasti;
50205032
return result;
@@ -5281,7 +5293,7 @@ PyEval_GetFuncDesc(PyObject *func)
52815293
#define C_TRACE(x, call) \
52825294
if (tstate->use_tracing && tstate->c_profilefunc) { \
52835295
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
5284-
tstate, tstate->frame, \
5296+
tstate, tstate->frame, bounds, \
52855297
PyTrace_C_CALL, func)) { \
52865298
x = NULL; \
52875299
} \
@@ -5291,13 +5303,13 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
52915303
if (x == NULL) { \
52925304
call_trace_protected(tstate->c_profilefunc, \
52935305
tstate->c_profileobj, \
5294-
tstate, tstate->frame, \
5306+
tstate, tstate->frame, bounds, \
52955307
PyTrace_C_EXCEPTION, func); \
52965308
/* XXX should pass (type, value, tb) */ \
52975309
} else { \
52985310
if (call_trace(tstate->c_profilefunc, \
52995311
tstate->c_profileobj, \
5300-
tstate, tstate->frame, \
5312+
tstate, tstate->frame, bounds, \
53015313
PyTrace_C_RETURN, func)) { \
53025314
Py_DECREF(x); \
53035315
x = NULL; \
@@ -5312,6 +5324,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
53125324

53135325
static PyObject *
53145326
trace_call_function(PyThreadState *tstate,
5327+
PyCodeAddressRange *bounds,
53155328
PyObject *func,
53165329
PyObject **args, Py_ssize_t nargs,
53175330
PyObject *kwnames)
@@ -5346,7 +5359,11 @@ trace_call_function(PyThreadState *tstate,
53465359
/* Issue #29227: Inline call_function() into _PyEval_EvalFrameDefault()
53475360
to reduce the stack consumption. */
53485361
Py_LOCAL_INLINE(PyObject *) _Py_HOT_FUNCTION
5349-
call_function(PyThreadState *tstate, PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
5362+
call_function(PyThreadState *tstate,
5363+
PyCodeAddressRange *bounds,
5364+
PyObject ***pp_stack,
5365+
Py_ssize_t oparg,
5366+
PyObject *kwnames)
53505367
{
53515368
PyObject **pfunc = (*pp_stack) - oparg - 1;
53525369
PyObject *func = *pfunc;
@@ -5356,7 +5373,7 @@ call_function(PyThreadState *tstate, PyObject ***pp_stack, Py_ssize_t oparg, PyO
53565373
PyObject **stack = (*pp_stack) - nargs - nkwargs;
53575374

53585375
if (tstate->use_tracing) {
5359-
x = trace_call_function(tstate, func, stack, nargs, kwnames);
5376+
x = trace_call_function(tstate, bounds, func, stack, nargs, kwnames);
53605377
}
53615378
else {
53625379
x = PyObject_Vectorcall(func, stack, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
@@ -5374,7 +5391,11 @@ call_function(PyThreadState *tstate, PyObject ***pp_stack, Py_ssize_t oparg, PyO
53745391
}
53755392

53765393
static PyObject *
5377-
do_call_core(PyThreadState *tstate, PyObject *func, PyObject *callargs, PyObject *kwdict)
5394+
do_call_core(PyThreadState *tstate,
5395+
PyCodeAddressRange *bounds,
5396+
PyObject *func,
5397+
PyObject *callargs,
5398+
PyObject *kwdict)
53785399
{
53795400
PyObject *result;
53805401

0 commit comments

Comments
 (0)