Skip to content

Commit

Permalink
gh-110892: Return NULL for PyTrace_RETURN events caused by an excep…
Browse files Browse the repository at this point in the history
…tion (GH-110909)
  • Loading branch information
gaogaotiantian committed Nov 2, 2023
1 parent 0887b9c commit f4b5588
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 23 deletions.
29 changes: 17 additions & 12 deletions Lib/test/test_sys_setprofile.py
Expand Up @@ -30,9 +30,9 @@ def callback(self, frame, event, arg):
if (event == "call"
or event == "return"
or event == "exception"):
self.add_event(event, frame)
self.add_event(event, frame, arg)

def add_event(self, event, frame=None):
def add_event(self, event, frame=None, arg=None):
"""Add an event to the log."""
if frame is None:
frame = sys._getframe(1)
Expand All @@ -43,7 +43,7 @@ def add_event(self, event, frame=None):
frameno = len(self.frames)
self.frames.append(frame)

self.events.append((frameno, event, ident(frame)))
self.events.append((frameno, event, ident(frame), arg))

def get_events(self):
"""Remove calls to add_event()."""
Expand Down Expand Up @@ -89,11 +89,16 @@ def trace_pass(self, frame):


class TestCaseBase(unittest.TestCase):
def check_events(self, callable, expected):
def check_events(self, callable, expected, check_args=False):
events = capture_events(callable, self.new_watcher())
if events != expected:
self.fail("Expected events:\n%s\nReceived events:\n%s"
% (pprint.pformat(expected), pprint.pformat(events)))
if check_args:
if events != expected:
self.fail("Expected events:\n%s\nReceived events:\n%s"
% (pprint.pformat(expected), pprint.pformat(events)))
else:
if [(frameno, event, ident) for frameno, event, ident, arg in events] != expected:
self.fail("Expected events:\n%s\nReceived events:\n%s"
% (pprint.pformat(expected), pprint.pformat(events)))


class ProfileHookTestCase(TestCaseBase):
Expand Down Expand Up @@ -264,11 +269,11 @@ def g(p):

f_ident = ident(f)
g_ident = ident(g)
self.check_events(g, [(1, 'call', g_ident),
(2, 'call', f_ident),
(2, 'return', f_ident),
(1, 'return', g_ident),
])
self.check_events(g, [(1, 'call', g_ident, None),
(2, 'call', f_ident, None),
(2, 'return', f_ident, 0),
(1, 'return', g_ident, None),
], check_args=True)

def test_stop_iteration(self):
def f():
Expand Down
@@ -0,0 +1 @@
Return ``NULL`` for ``PyTrace_RETURN`` events caused by an exception
42 changes: 31 additions & 11 deletions Python/legacy_tracing.c
Expand Up @@ -46,7 +46,7 @@ call_profile_func(_PyLegacyEventHandler *self, PyObject *arg)
}

static PyObject *
sys_profile_func2(
sys_profile_start(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
Expand All @@ -56,7 +56,17 @@ sys_profile_func2(
}

static PyObject *
sys_profile_func3(
sys_profile_throw(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
assert(kwnames == NULL);
assert(PyVectorcall_NARGS(nargsf) == 3);
return call_profile_func(self, Py_None);
}

static PyObject *
sys_profile_return(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
Expand All @@ -72,7 +82,7 @@ sys_profile_unwind(
) {
assert(kwnames == NULL);
assert(PyVectorcall_NARGS(nargsf) == 3);
return call_profile_func(self, Py_None);
return call_profile_func(self, NULL);
}

static PyObject *
Expand Down Expand Up @@ -154,7 +164,7 @@ sys_trace_exception_func(
}

static PyObject *
sys_trace_func2(
sys_trace_start(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
Expand All @@ -164,7 +174,7 @@ sys_trace_func2(
}

static PyObject *
sys_trace_func3(
sys_trace_throw(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
Expand All @@ -173,6 +183,16 @@ sys_trace_func3(
return call_trace_func(self, Py_None);
}

static PyObject *
sys_trace_unwind(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
assert(kwnames == NULL);
assert(PyVectorcall_NARGS(nargsf) == 3);
return call_trace_func(self, NULL);
}

static PyObject *
sys_trace_return(
_PyLegacyEventHandler *self, PyObject *const *args,
Expand Down Expand Up @@ -373,17 +393,17 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
if (!tstate->interp->sys_profile_initialized) {
tstate->interp->sys_profile_initialized = true;
if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
(vectorcallfunc)sys_profile_func2, PyTrace_CALL,
(vectorcallfunc)sys_profile_start, PyTrace_CALL,
PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
return -1;
}
if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
(vectorcallfunc)sys_profile_func3, PyTrace_CALL,
(vectorcallfunc)sys_profile_throw, PyTrace_CALL,
PY_MONITORING_EVENT_PY_THROW, -1)) {
return -1;
}
if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
(vectorcallfunc)sys_profile_func3, PyTrace_RETURN,
(vectorcallfunc)sys_profile_return, PyTrace_RETURN,
PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) {
return -1;
}
Expand Down Expand Up @@ -447,12 +467,12 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
if (!tstate->interp->sys_trace_initialized) {
tstate->interp->sys_trace_initialized = true;
if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
(vectorcallfunc)sys_trace_func2, PyTrace_CALL,
(vectorcallfunc)sys_trace_start, PyTrace_CALL,
PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
return -1;
}
if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
(vectorcallfunc)sys_trace_func3, PyTrace_CALL,
(vectorcallfunc)sys_trace_throw, PyTrace_CALL,
PY_MONITORING_EVENT_PY_THROW, -1)) {
return -1;
}
Expand All @@ -477,7 +497,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
return -1;
}
if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
(vectorcallfunc)sys_trace_func3, PyTrace_RETURN,
(vectorcallfunc)sys_trace_unwind, PyTrace_RETURN,
PY_MONITORING_EVENT_PY_UNWIND, -1)) {
return -1;
}
Expand Down

0 comments on commit f4b5588

Please sign in to comment.