Skip to content

Commit fb8f208

Browse files
authored
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().
1 parent 61190e0 commit fb8f208

File tree

2 files changed

+37
-23
lines changed

2 files changed

+37
-23
lines changed

Include/cpython/abstract.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ PyVectorcall_Function(PyObject *callable)
7171
return NULL;
7272
}
7373
assert(PyCallable_Check(callable));
74+
7475
offset = tp->tp_vectorcall_offset;
7576
assert(offset > 0);
7677
memcpy(&ptr, (char *) callable + offset, sizeof(ptr));

Objects/call.c

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -225,28 +225,11 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
225225
}
226226

227227

228-
PyObject *
229-
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
228+
static PyObject *
229+
_PyVectorcall_Call(PyThreadState *tstate, vectorcallfunc func,
230+
PyObject *callable, PyObject *tuple, PyObject *kwargs)
230231
{
231-
PyThreadState *tstate = _PyThreadState_GET();
232-
vectorcallfunc func;
233-
234-
/* get vectorcallfunc as in PyVectorcall_Function, but without
235-
* the Py_TPFLAGS_HAVE_VECTORCALL check */
236-
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
237-
if (offset <= 0) {
238-
_PyErr_Format(tstate, PyExc_TypeError,
239-
"'%.200s' object does not support vectorcall",
240-
Py_TYPE(callable)->tp_name);
241-
return NULL;
242-
}
243-
memcpy(&func, (char *) callable + offset, sizeof(func));
244-
if (func == NULL) {
245-
_PyErr_Format(tstate, PyExc_TypeError,
246-
"'%.200s' object does not support vectorcall",
247-
Py_TYPE(callable)->tp_name);
248-
return NULL;
249-
}
232+
assert(func != NULL);
250233

251234
Py_ssize_t nargs = PyTuple_GET_SIZE(tuple);
252235

@@ -272,6 +255,35 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
272255
}
273256

274257

258+
PyObject *
259+
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
260+
{
261+
PyThreadState *tstate = _PyThreadState_GET();
262+
263+
/* get vectorcallfunc as in PyVectorcall_Function, but without
264+
* the Py_TPFLAGS_HAVE_VECTORCALL check */
265+
Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
266+
if (offset <= 0) {
267+
_PyErr_Format(tstate, PyExc_TypeError,
268+
"'%.200s' object does not support vectorcall",
269+
Py_TYPE(callable)->tp_name);
270+
return NULL;
271+
}
272+
assert(PyCallable_Check(callable));
273+
274+
vectorcallfunc func;
275+
memcpy(&func, (char *) callable + offset, sizeof(func));
276+
if (func == NULL) {
277+
_PyErr_Format(tstate, PyExc_TypeError,
278+
"'%.200s' object does not support vectorcall",
279+
Py_TYPE(callable)->tp_name);
280+
return NULL;
281+
}
282+
283+
return _PyVectorcall_Call(tstate, func, callable, tuple, kwargs);
284+
}
285+
286+
275287
PyObject *
276288
_PyObject_Call(PyThreadState *tstate, PyObject *callable,
277289
PyObject *args, PyObject *kwargs)
@@ -286,8 +298,9 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable,
286298
assert(PyTuple_Check(args));
287299
assert(kwargs == NULL || PyDict_Check(kwargs));
288300

289-
if (PyVectorcall_Function(callable) != NULL) {
290-
return PyVectorcall_Call(callable, args, kwargs);
301+
vectorcallfunc vector_func = PyVectorcall_Function(callable);
302+
if (vector_func != NULL) {
303+
return _PyVectorcall_Call(tstate, vector_func, callable, args, kwargs);
291304
}
292305
else {
293306
call = Py_TYPE(callable)->tp_call;

0 commit comments

Comments
 (0)