From b4e41f42fc0d0d07c18a8e2b752699c379ad3c78 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 8 Feb 2017 12:06:00 +0100 Subject: Issue #29306: Fix usage of Py_EnterRecursiveCall() * *PyCFunction_*Call*() functions now call Py_EnterRecursiveCall(). * PyObject_Call() now calls directly _PyFunction_FastCallDict() and PyCFunction_Call() to avoid calling Py_EnterRecursiveCall() twice per function call --- Objects/methodobject.c | 61 +++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'Objects/methodobject.c') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 6618d78968..07827775ca 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -90,11 +90,6 @@ PyObject * _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - PyCFunction meth; - PyObject *result; - int flags; - PyObject *argstuple; - /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ @@ -105,18 +100,23 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - meth = method->ml_meth; - flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } switch (flags) { case METH_NOARGS: - if (nargs != 0) { + if (nargs != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", method->ml_name, nargs); - return NULL; - } + goto exit; + } if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { goto no_keyword_error; @@ -130,7 +130,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { @@ -148,10 +148,11 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg /* fall through next case */ case METH_VARARGS | METH_KEYWORDS: + { /* Slow-path: create a temporary tuple for positional arguments */ - argstuple = _PyStack_AsTuple(args, nargs); + PyObject *argstuple = _PyStack_AsTuple(args, nargs); if (argstuple == NULL) { - return NULL; + goto exit; } if (flags & METH_KEYWORDS) { @@ -162,6 +163,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg } Py_DECREF(argstuple); break; + } case METH_FASTCALL: { @@ -170,7 +172,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { - return NULL; + goto exit; } result = (*fastmeth) (self, stack, nargs, kwnames); @@ -185,17 +187,19 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyErr_SetString(PyExc_SystemError, "Bad call flags in _PyMethodDef_RawFastCallDict. " "METH_OLDARGS is no longer supported!"); - return NULL; + goto exit; } - return result; + goto exit; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", method->ml_name, nargs); - return NULL; +exit: + Py_LeaveRecursiveCall(); + return result; } PyObject * @@ -232,7 +236,11 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyCFunction meth = method->ml_meth; int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); - PyObject *result; + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } switch (flags) { @@ -241,7 +249,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (nkwargs) { @@ -256,7 +264,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (nkwargs) { @@ -284,7 +292,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * argtuple = _PyStack_AsTuple(args, nargs); if (argtuple == NULL) { - return NULL; + goto exit; } if (flags & METH_KEYWORDS) { @@ -294,7 +302,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * kwdict = _PyStack_AsDict(args + nargs, kwnames); if (kwdict == NULL) { Py_DECREF(argtuple); - return NULL; + goto exit; } } else { @@ -315,16 +323,19 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_SetString(PyExc_SystemError, "Bad call flags in _PyCFunction_FastCallKeywords. " "METH_OLDARGS is no longer supported!"); - return NULL; + goto exit; } - return result; + goto exit; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", method->ml_name); - return NULL; + +exit: + Py_LeaveRecursiveCall(); + return result; } PyObject * -- cgit v1.2.1