]> granicus.if.org Git - python/commitdiff
bpo-29676: fix lsprof can't profile C method call. (GH523)
authorINADA Naoki <methane@users.noreply.github.com>
Tue, 7 Mar 2017 05:24:37 +0000 (14:24 +0900)
committerGitHub <noreply@github.com>
Tue, 7 Mar 2017 05:24:37 +0000 (14:24 +0900)
When LOAD_METHOD is used for calling C mehtod, PyMethodDescrObject
was passed to profilefunc from 5566bbb.
But lsprof traces only PyCFunctionObject. Additionally, there can be
some third party extension which assumes passed arg is
PyCFunctionObject without calling PyCFunction_Check().

So make PyCFunctionObject from PyMethodDescrObject when
tstate->c_profilefunc is set.

Python/ceval.c

index 49177d8e0587bc71d7504ae0f16615b007387fd2..e682fc1afd0ed0ec73e8d15c4f3b2407ed459f9c 100644 (file)
@@ -4818,7 +4818,20 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
     }
     else if (Py_TYPE(func) == &PyMethodDescr_Type) {
         PyThreadState *tstate = PyThreadState_GET();
-        C_TRACE(x, _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames));
+        if (tstate->use_tracing && tstate->c_profilefunc) {
+            // We need to create PyCFunctionObject for tracing.
+            PyMethodDescrObject *descr = (PyMethodDescrObject*)func;
+            func = PyCFunction_NewEx(descr->d_method, stack[0], NULL);
+            if (func == NULL) {
+                return NULL;
+            }
+            C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack+1, nargs-1,
+                                                     kwnames));
+            Py_DECREF(func);
+        }
+        else {
+            x = _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames);
+        }
     }
     else {
         if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {