summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-07-23 22:25:26 (GMT)
committerGitHub <noreply@github.com>2024-07-23 22:25:26 (GMT)
commite91ef13861e88c27aed51a24e58d1dcc855a01dc (patch)
tree51dc07c53bc50d877609d63385b07f120b980b9b
parent41a91bd67f86c922f350894a797738038536e1c5 (diff)
downloadcpython-e91ef13861e88c27aed51a24e58d1dcc855a01dc.zip
cpython-e91ef13861e88c27aed51a24e58d1dcc855a01dc.tar.gz
cpython-e91ef13861e88c27aed51a24e58d1dcc855a01dc.tar.bz2
gh-122029: Log call events in sys.setprofile when it's a method with c function (GH-122072)
Log call events in sys.setprofile when it is a method with a C function.
-rw-r--r--Lib/test/test_sys_setprofile.py14
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst1
-rw-r--r--Python/legacy_tracing.c13
3 files changed, 28 insertions, 0 deletions
diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py
index 32e03d7..b2e8e8a 100644
--- a/Lib/test/test_sys_setprofile.py
+++ b/Lib/test/test_sys_setprofile.py
@@ -479,6 +479,20 @@ class TestEdgeCases(unittest.TestCase):
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()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst
new file mode 100644
index 0000000..bddee3a
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst
@@ -0,0 +1 @@
+Emit ``c_call`` events in :func:`sys.setprofile` when a ``PyMethodObject`` pointing to a ``PyCFunction`` is called.
diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c
index 1103d99..9cc3af1 100644
--- a/Python/legacy_tracing.c
+++ b/Python/legacy_tracing.c
@@ -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;
}