Skip to content

Commit

Permalink
[3.13] pythongh-122029: Log call events in sys.setprofile when it's a…
Browse files Browse the repository at this point in the history
… method with c function (pythonGH-122072) (pythonGH-122205)

pythongh-122029: Log call events in sys.setprofile when it's a method with c function (pythonGH-122072)

Log call events in sys.setprofile when it is a method with a C function.
(cherry picked from commit e91ef13)

Co-authored-by: Tian Gao <[email protected]>
  • Loading branch information
miss-islington and gaogaotiantian authored Jul 23, 2024
1 parent 81f9339 commit 40cdec6
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Lib/test/test_sys_setprofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,20 @@ def f():
sys.setprofile(lambda *args: None)
f()

def test_method_with_c_function(self):
# gh-122029
# When we have a PyMethodObject whose im_func is a C function, we
# should record both the call and the return. f = classmethod(repr)
# is just a way to create a PyMethodObject with a C function.
class A:
f = classmethod(repr)
events = []
sys.setprofile(lambda frame, event, args: events.append(event))
A().f()
sys.setprofile(None)
# The last c_call is the call to sys.setprofile
self.assertEqual(events, ['c_call', 'c_return', 'c_call'])


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Emit ``c_call`` events in :func:`sys.setprofile` when a ``PyMethodObject`` pointing to a ``PyCFunction`` is called.
13 changes: 13 additions & 0 deletions Python/legacy_tracing.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ sys_profile_call_or_return(
Py_DECREF(meth);
return res;
}
else if (Py_TYPE(callable) == &PyMethod_Type) {
// CALL instruction will grab the function from the method,
// so if the function is a C function, the return event will
// be emitted. However, CALL event happens before CALL
// instruction, so we need to handle this case here.
PyObject* func = PyMethod_GET_FUNCTION(callable);
if (func == NULL) {
return NULL;
}
if (PyCFunction_Check(func)) {
return call_profile_func(self, func);
}
}
Py_RETURN_NONE;
}

Expand Down

0 comments on commit 40cdec6

Please sign in to comment.