From fb8f208a4ddb38eedee71f9ecd0f22058802dab1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 12 Oct 2021 00:18:26 +0200 Subject: bpo-45439: _PyObject_Call() only checks tp_vectorcall_offset once (GH-28890) Add _PyVectorcall_Call() helper function. Add "assert(PyCallable_Check(callable));" to PyVectorcall_Call(), similar check than PyVectorcall_Function(). --- Include/cpython/abstract.h | 1 + Objects/call.c | 59 ++++++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index db85021..ea269f7 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -71,6 +71,7 @@ PyVectorcall_Function(PyObject *callable) return NULL; } assert(PyCallable_Check(callable)); + offset = tp->tp_vectorcall_offset; assert(offset > 0); memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); diff --git a/Objects/call.c b/Objects/call.c index 960c37e..ecf6e68 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -225,28 +225,11 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, } -PyObject * -PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) +static PyObject * +_PyVectorcall_Call(PyThreadState *tstate, vectorcallfunc func, + PyObject *callable, PyObject *tuple, PyObject *kwargs) { - PyThreadState *tstate = _PyThreadState_GET(); - vectorcallfunc func; - - /* get vectorcallfunc as in PyVectorcall_Function, but without - * the Py_TPFLAGS_HAVE_VECTORCALL check */ - Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset; - if (offset <= 0) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support vectorcall", - Py_TYPE(callable)->tp_name); - return NULL; - } - memcpy(&func, (char *) callable + offset, sizeof(func)); - if (func == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support vectorcall", - Py_TYPE(callable)->tp_name); - return NULL; - } + assert(func != NULL); Py_ssize_t nargs = PyTuple_GET_SIZE(tuple); @@ -273,6 +256,35 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) PyObject * +PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) +{ + PyThreadState *tstate = _PyThreadState_GET(); + + /* get vectorcallfunc as in PyVectorcall_Function, but without + * the Py_TPFLAGS_HAVE_VECTORCALL check */ + Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset; + if (offset <= 0) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support vectorcall", + Py_TYPE(callable)->tp_name); + return NULL; + } + assert(PyCallable_Check(callable)); + + vectorcallfunc func; + memcpy(&func, (char *) callable + offset, sizeof(func)); + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support vectorcall", + Py_TYPE(callable)->tp_name); + return NULL; + } + + return _PyVectorcall_Call(tstate, func, callable, tuple, kwargs); +} + + +PyObject * _PyObject_Call(PyThreadState *tstate, PyObject *callable, PyObject *args, PyObject *kwargs) { @@ -286,8 +298,9 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable, assert(PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); - if (PyVectorcall_Function(callable) != NULL) { - return PyVectorcall_Call(callable, args, kwargs); + vectorcallfunc vector_func = PyVectorcall_Function(callable); + if (vector_func != NULL) { + return _PyVectorcall_Call(tstate, vector_func, callable, args, kwargs); } else { call = Py_TYPE(callable)->tp_call; -- cgit v0.12