summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_sys_setprofile.py18
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst1
-rw-r--r--Python/ceval.c30
3 files changed, 46 insertions, 3 deletions
diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py
index 16467e7f71..c2ecf8eeed 100644
--- a/Lib/test/test_sys_setprofile.py
+++ b/Lib/test/test_sys_setprofile.py
@@ -350,6 +350,24 @@ class ProfileSimulatorTestCase(TestCaseBase):
self.check_events(f, [(1, 'call', f_ident),
(1, 'return', f_ident)])
+ # Test an invalid call (bpo-34125)
+ def test_unbound_method_no_args(self):
+ kwargs = {}
+ def f(p):
+ dict.get(**kwargs)
+ f_ident = ident(f)
+ self.check_events(f, [(1, 'call', f_ident),
+ (1, 'return', f_ident)])
+
+ # Test an invalid call (bpo-34125)
+ def test_unbound_method_invalid_args(self):
+ kwargs = {}
+ def f(p):
+ dict.get(print, 42, **kwargs)
+ f_ident = ident(f)
+ self.check_events(f, [(1, 'call', f_ident),
+ (1, 'return', f_ident)])
+
def ident(function):
if hasattr(function, "f_code"):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst b/Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst
new file mode 100644
index 0000000000..e6036b4d41
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst
@@ -0,0 +1 @@
+Profiling of unbound built-in methods now works when ``**kwargs`` is given.
diff --git a/Python/ceval.c b/Python/ceval.c
index 4a82bd3198..d0f9915b4f 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4642,15 +4642,39 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
static PyObject *
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
{
+ PyObject *result;
+
if (PyCFunction_Check(func)) {
- PyObject *result;
PyThreadState *tstate = PyThreadState_GET();
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
return result;
}
- else {
- return PyObject_Call(func, callargs, kwdict);
+ else if (Py_TYPE(func) == &PyMethodDescr_Type) {
+ PyThreadState *tstate = PyThreadState_GET();
+ Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
+ if (nargs > 0 && tstate->use_tracing) {
+ /* We need to create a temporary bound method as argument
+ for profiling.
+
+ If nargs == 0, then this cannot work because we have no
+ "self". In any case, the call itself would raise
+ TypeError (foo needs an argument), so we just skip
+ profiling. */
+ PyObject *self = PyTuple_GET_ITEM(callargs, 0);
+ func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
+ if (func == NULL) {
+ return NULL;
+ }
+
+ C_TRACE(result, _PyCFunction_FastCallDict(func,
+ &PyTuple_GET_ITEM(callargs, 1),
+ nargs - 1,
+ kwdict));
+ Py_DECREF(func);
+ return result;
+ }
}
+ return PyObject_Call(func, callargs, kwdict);
}
/* Extract a slice index from a PyLong or an object with the