Skip to content

Commit 257c413

Browse files
[3.12] gh-122029: Log call events in sys.setprofile when it's a method with c function (GH-122072) (GH-122206)
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. (cherry picked from commit e91ef13) Co-authored-by: Tian Gao <[email protected]>
1 parent d7c67e0 commit 257c413

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

Lib/test/test_sys_setprofile.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,20 @@ def f():
478478
sys.setprofile(lambda *args: None)
479479
f()
480480

481+
def test_method_with_c_function(self):
482+
# gh-122029
483+
# When we have a PyMethodObject whose im_func is a C function, we
484+
# should record both the call and the return. f = classmethod(repr)
485+
# is just a way to create a PyMethodObject with a C function.
486+
class A:
487+
f = classmethod(repr)
488+
events = []
489+
sys.setprofile(lambda frame, event, args: events.append(event))
490+
A().f()
491+
sys.setprofile(None)
492+
# The last c_call is the call to sys.setprofile
493+
self.assertEqual(events, ['c_call', 'c_return', 'c_call'])
494+
481495

482496
if __name__ == "__main__":
483497
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Emit ``c_call`` events in :func:`sys.setprofile` when a ``PyMethodObject`` pointing to a ``PyCFunction`` is called.

Python/legacy_tracing.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ sys_profile_call_or_return(
103103
Py_DECREF(meth);
104104
return res;
105105
}
106+
else if (Py_TYPE(callable) == &PyMethod_Type) {
107+
// CALL instruction will grab the function from the method,
108+
// so if the function is a C function, the return event will
109+
// be emitted. However, CALL event happens before CALL
110+
// instruction, so we need to handle this case here.
111+
PyObject* func = PyMethod_GET_FUNCTION(callable);
112+
if (func == NULL) {
113+
return NULL;
114+
}
115+
if (PyCFunction_Check(func)) {
116+
return call_profile_func(self, func);
117+
}
118+
}
106119
Py_RETURN_NONE;
107120
}
108121

0 commit comments

Comments
 (0)