Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.13] gh-129502: Fix handling errors in ctypes callbacks (GH-129504) #129517

Merged
merged 2 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Unlikely errors in preparing arguments for :mod:`ctypes` callback are now
handled in the same way as errors raised in the callback of in converting
the result of the callback -- using :func:`sys.unraisablehook` instead of
:func:`sys.excepthook` and not setting :data:`sys.last_exc` and other
variables.
66 changes: 30 additions & 36 deletions Modules/_ctypes/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,6 @@ PyType_Spec cthunk_spec = {

/**************************************************************/

static void
PrintError(const char *msg, ...)
{
char buf[512];
PyObject *f = PySys_GetObject("stderr");
va_list marker;

va_start(marker, msg);
PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
va_end(marker);
if (f != NULL && f != Py_None)
PyFile_WriteString(buf, f);
PyErr_Print();
}


#ifdef MS_WIN32
/*
* We must call AddRef() on non-NULL COM pointers we receive as arguments
Expand All @@ -108,26 +92,23 @@ PrintError(const char *msg, ...)
* after checking for PyObject_IsTrue(), but this would probably be somewhat
* slower.
*/
static void
static int
TryAddRef(PyObject *cnv, CDataObject *obj)
{
IUnknown *punk;
PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv);
if (!attrdict) {
return;
return 0;
}
int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_));
if (r <= 0) {
if (r < 0) {
PrintError("getting _needs_com_addref_");
}
return;
return r;
}

punk = *(IUnknown **)obj->b_ptr;
if (punk)
punk->lpVtbl->AddRef(punk);
return;
return 0;
}
#endif

Expand Down Expand Up @@ -162,14 +143,13 @@ static void _CallPythonObject(ctypes_state *st,

StgInfo *info;
if (PyStgInfo_FromType(st, cnv, &info) < 0) {
goto Done;
goto Error;
}

if (info && info->getfunc && !_ctypes_simple_instance(st, cnv)) {
PyObject *v = info->getfunc(*pArgs, info->size);
if (!v) {
PrintError("create argument %zd:\n", i);
goto Done;
goto Error;
}
args[i] = v;
/* XXX XXX XX
Expand All @@ -182,33 +162,39 @@ static void _CallPythonObject(ctypes_state *st,
/* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
if (!obj) {
PrintError("create argument %zd:\n", i);
goto Done;
goto Error;
}
if (!CDataObject_Check(st, obj)) {
PyErr_Format(PyExc_TypeError,
"%R returned unexpected result of type %T", cnv, obj);
Py_DECREF(obj);
PrintError("unexpected result of create argument %zd:\n", i);
goto Done;
goto Error;
}
memcpy(obj->b_ptr, *pArgs, info->size);
args[i] = (PyObject *)obj;
#ifdef MS_WIN32
TryAddRef(cnv, obj);
if (TryAddRef(cnv, obj) < 0) {
goto Error;
}
#endif
} else {
PyErr_SetString(PyExc_TypeError,
"cannot build parameter");
PrintError("Parsing argument %zd\n", i);
goto Done;
PyErr_Format(PyExc_TypeError,
"cannot build parameter of type %R", cnv);
goto Error;
}
/* XXX error handling! */
pArgs++;
}

if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
error_object = _ctypes_get_errobj(st, &space);
if (error_object == NULL)
if (error_object == NULL) {
PyErr_FormatUnraisable(
"Exception ignored while setting error for "
"ctypes callback function %R",
callable);
goto Done;
}
if (flags & FUNCFLAG_USE_ERRNO) {
int temp = space[0];
space[0] = errno;
Expand Down Expand Up @@ -295,6 +281,14 @@ static void _CallPythonObject(ctypes_state *st,
for (j = 0; j < i; j++) {
Py_DECREF(args[j]);
}
return;

Error:
PyErr_FormatUnraisable(
"Exception ignored while creating argument %zd for "
"ctypes callback function %R",
i, callable);
goto Done;
}

static void closure_fcn(ffi_cif *cif,
Expand Down
Loading