Skip to content

Commit 3601906

Browse files
gaogaotiantiannohlson
authored andcommitted
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.
1 parent f3210d3 commit 3601906

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

Lib/test/test_sys_setprofile.py

+14
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,20 @@ def f():
479479
sys.setprofile(lambda *args: None)
480480
f()
481481

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

483497
if __name__ == "__main__":
484498
unittest.main()
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

+13
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@ sys_profile_call_or_return(
121121
Py_DECREF(meth);
122122
return res;
123123
}
124+
else if (Py_TYPE(callable) == &PyMethod_Type) {
125+
// CALL instruction will grab the function from the method,
126+
// so if the function is a C function, the return event will
127+
// be emitted. However, CALL event happens before CALL
128+
// instruction, so we need to handle this case here.
129+
PyObject* func = PyMethod_GET_FUNCTION(callable);
130+
if (func == NULL) {
131+
return NULL;
132+
}
133+
if (PyCFunction_Check(func)) {
134+
return call_profile_func(self, func);
135+
}
136+
}
124137
Py_RETURN_NONE;
125138
}
126139

0 commit comments

Comments
 (0)