Skip to content

Commit

Permalink
bpo-46323: Use PyObject_Vectorcall while calling ctypes callback func…
Browse files Browse the repository at this point in the history
…tion (GH-31138)
  • Loading branch information
corona10 committed Feb 8, 2022
1 parent 69e1097 commit b552768
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 38 deletions.
@@ -0,0 +1,2 @@
Use :c:func:`PyObject_Vectorcall` while calling ctypes callback function.
Patch by Dong-hee Na.
78 changes: 40 additions & 38 deletions Modules/_ctypes/callbacks.c
Expand Up @@ -146,47 +146,48 @@ static void _CallPythonObject(void *mem,
int flags,
void **pArgs)
{
Py_ssize_t i;
PyObject *result;
PyObject *arglist = NULL;
Py_ssize_t nArgs;
PyObject *result = NULL;
PyObject **args = NULL;
Py_ssize_t i = 0, j = 0, nargs = 0;
PyObject *error_object = NULL;
int *space;
PyGILState_STATE state = PyGILState_Ensure();

nArgs = PySequence_Length(converters);
assert(PyTuple_Check(converters));
nargs = PyTuple_GET_SIZE(converters);
/* Hm. What to return in case of error?
For COM, 0xFFFFFFFF seems better than 0.
*/
if (nArgs < 0) {
if (nargs < 0) {
PrintError("BUG: PySequence_Length");
goto Done;
}

arglist = PyTuple_New(nArgs);
if (!arglist) {
PrintError("PyTuple_New()");
goto Done;
PyObject *args_stack[CTYPES_MAX_ARGCOUNT];
if (nargs <= CTYPES_MAX_ARGCOUNT) {
args = args_stack;
}
for (i = 0; i < nArgs; ++i) {
/* Note: new reference! */
PyObject *cnv = PySequence_GetItem(converters, i);
StgDictObject *dict;
if (cnv)
dict = PyType_stgdict(cnv);
else {
PrintError("Getting argument converter %zd\n", i);
else {
args = PyMem_Malloc(nargs * sizeof(PyObject *));
if (args == NULL) {
PyErr_NoMemory();
goto Done;
}
}

PyObject **cnvs = PySequence_Fast_ITEMS(converters);
for (i = 0; i < nargs; i++) {
PyObject *cnv = cnvs[i]; // borrowed ref
StgDictObject *dict;
dict = PyType_stgdict(cnv);

if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
PyObject *v = dict->getfunc(*pArgs, dict->size);
if (!v) {
PrintError("create argument %zd:\n", i);
Py_DECREF(cnv);
goto Done;
}
PyTuple_SET_ITEM(arglist, i, v);
args[i] = v;
/* XXX XXX XX
We have the problem that c_byte or c_short have dict->size of
1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
Expand All @@ -202,23 +203,20 @@ static void _CallPythonObject(void *mem,
}
if (!CDataObject_Check(obj)) {
Py_DECREF(obj);
Py_DECREF(cnv);
PrintError("unexpected result of create argument %zd:\n", i);
goto Done;
}
memcpy(obj->b_ptr, *pArgs, dict->size);
PyTuple_SET_ITEM(arglist, i, (PyObject *)obj);
args[i] = (PyObject *)obj;
#ifdef MS_WIN32
TryAddRef(dict, obj);
#endif
} else {
PyErr_SetString(PyExc_TypeError,
"cannot build parameter");
PrintError("Parsing argument %zd\n", i);
Py_DECREF(cnv);
goto Done;
}
Py_DECREF(cnv);
/* XXX error handling! */
pArgs++;
}
Expand All @@ -241,7 +239,7 @@ static void _CallPythonObject(void *mem,
#endif
}

result = PyObject_CallObject(callable, arglist);
result = PyObject_Vectorcall(callable, args, nargs, NULL);
if (result == NULL) {
_PyErr_WriteUnraisableMsg("on calling ctypes callback function",
callable);
Expand Down Expand Up @@ -308,7 +306,12 @@ static void _CallPythonObject(void *mem,
Py_XDECREF(result);

Done:
Py_XDECREF(arglist);
for (j = 0; j < i; j++) {
Py_DECREF(args[j]);
}
if (args != args_stack) {
PyMem_Free(args);
}
PyGILState_Release(state);
}

Expand All @@ -328,12 +331,12 @@ static void closure_fcn(ffi_cif *cif,
args);
}

static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
{
CThunkObject *p;
Py_ssize_t i;

p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
if (p == NULL) {
return NULL;
}
Expand All @@ -348,7 +351,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
p->setfunc = NULL;
p->ffi_restype = NULL;

for (i = 0; i < nArgs + 1; ++i)
for (i = 0; i < nargs + 1; ++i)
p->atypes[i] = NULL;
PyObject_GC_Track((PyObject *)p);
return p;
Expand All @@ -361,11 +364,12 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
{
int result;
CThunkObject *p;
Py_ssize_t nArgs, i;
Py_ssize_t nargs, i;
ffi_abi cc;

nArgs = PySequence_Size(converters);
p = CThunkObject_new(nArgs);
assert(PyTuple_Check(converters));
nargs = PyTuple_GET_SIZE(converters);
p = CThunkObject_new(nargs);
if (p == NULL)
return NULL;

Expand All @@ -378,12 +382,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
}

p->flags = flags;
for (i = 0; i < nArgs; ++i) {
PyObject *cnv = PySequence_GetItem(converters, i);
if (cnv == NULL)
goto error;
PyObject **cnvs = PySequence_Fast_ITEMS(converters);
for (i = 0; i < nargs; ++i) {
PyObject *cnv = cnvs[i]; // borrowed ref
p->atypes[i] = _ctypes_get_ffi_type(cnv);
Py_DECREF(cnv);
}
p->atypes[i] = NULL;

Expand All @@ -409,7 +411,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
cc = FFI_STDCALL;
#endif
result = ffi_prep_cif(&p->cif, cc,
Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int),
Py_SAFE_DOWNCAST(nargs, Py_ssize_t, int),
_ctypes_get_ffi_type(restype),
&p->atypes[0]);
if (result != FFI_OK) {
Expand Down

0 comments on commit b552768

Please sign in to comment.