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().
This commit is contained in:
Victor Stinner 2021-10-12 00:18:26 +02:00 committed by GitHub
parent 61190e092b
commit fb8f208a4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 23 deletions

View File

@ -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));

View File

@ -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);
@ -272,6 +255,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;