8000 gh-129502: Fix handling errors in ctypes callbacks (GH-129504) · python/cpython@9d63ae5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9d63ae5

Browse files
gh-129502: Fix handling errors in ctypes callbacks (GH-129504)
Unlikely errors in preparing arguments for ctypes callback are now handled in the same way as errors raised in the callback of in converting the result of the callback -- using sys.unraisablehook() instead of sys.excepthook() and not setting sys.last_exc and other variables.
1 parent 3447f4a commit 9d63ae5

File tree

2 files changed

+35
-36
lines changed

2 files changed

+35
-36
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Unlikely errors in preparing arguments for :mod:`ctypes` callback are now
2+
handled in the same way as errors raised in the callback of in converting
3+
the result of the callback -- using :func:`sys.unraisablehook` instead of
4+
:func:`sys.excepthook` and not setting :data:`sys.last_exc` and other
5+
variables.

Modules/_ctypes/callbacks.c

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,6 @@ PyType_Spec cthunk_spec = {
8181

8282
/**************************************************************/
8383

84-
static void
85-
PrintError(const char *msg, ...)
86-
{
87-
char buf[512];
88-
PyObject *f = PySys_GetObject("stderr");
89-
va_list marker;
90-
91-
va_start(marker, msg);
92-
PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
93-
va_end(marker);
94-
if (f != NULL && f != Py_None)
95-
PyFile_WriteString(buf, f);
96-
PyErr_Print();
97-
}
98-
99-
10084
#ifdef MS_WIN32
10185
/*
10286
* We must call AddRef() on non-NULL COM pointers we receive as arguments
@@ -108,26 +92,23 @@ PrintError(const char *msg, ...)
10892
* after checking for PyObject_IsTrue(), but this would probably be somewhat
10993
* slower.
11094
*/
111-
static void
95+
static int
11296
TryAddRef(PyObject *cnv, CDataObject *obj)
11397
{
11498
IUnknown *punk;
11599
PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv);
116100
if (!attrdict) {
117-
return;
101+
return 0;
118102
}
119103
int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_));
120104
if (r <= 0) {
121-
if (r < 0) {
122-
PrintError("getting _needs_com_addref_");
123-
}
124-
return;
105+
return r;
125106
}
126107

127108
punk = *(IUnknown **)obj->b_ptr;
128109
if (punk)
129110
punk->lpVtbl->AddRef(punk);
130-
return;
111+
return 0;
131112
}
132113
#endif
133114

@@ -162,14 +143,13 @@ static void _CallPythonObject(ctypes_state *st,
162143

163144
StgInfo *info;
164145
if (PyStgInfo_FromType(st, cnv, &info) < 0) {
165-
goto Done;
146+
goto Error;
166147
}
167148

168149
if (info && info->getfunc && !_ctypes_simple_instance(st, cnv)) {
169150
PyObject *v = info->getfunc(*pArgs, info->size);
170151
if (!v) {
171-
PrintError("create argument %zd:\n", i);
172-
goto Done;
152+
goto Error;
173153
}
174154
args[i] = v;
175155
/* XXX XXX XX
@@ -182,33 +162,39 @@ static void _CallPythonObject(ctypes_state *st,
182162
/* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
183163
CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
184164
if (!obj) {
185-
PrintError("create argument %zd:\n", i);
186-
goto Done;
165+
goto Error;
187166
}
188167
if (!CDataObject_Check(st, obj)) {
168+
PyErr_Format(PyExc_TypeError,
169+
"%R returned unexpected result of type %T", cnv, obj);
189170
Py_DECREF(obj);
190-
PrintError("unexpected result of create argument %zd:\n", i);
191-
goto Done;
171+
goto Error;
192172
}
193173
memcpy(obj->b_ptr, *pArgs, info->size);
194174
args[i] = (PyObject *)obj;
195175
#ifdef MS_WIN32
196-
TryAddRef(cnv, obj);
176+
if (TryAddRef(cnv, obj) < 0) {
177+
goto Error;
178+
}
197179
#endif
198180
} else {
199-
PyErr_SetString(PyExc_TypeError,
200-
"cannot build parameter");
201-
PrintError("Parsing argument %zd\n", i);
202-
goto Done;
181+
PyErr_Format(PyExc_TypeError,
182+
"cannot build parameter of type %R", cnv);
183+
goto Error;
203184
}
204185
/* XXX error handling! */
205186
pArgs++;
206187
}
207188

208189
if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
209190
error_object = _ctypes_get_errobj(st, &space);
210-
if (error_object == NULL)
191+
if (error_object == NULL) {
192+
PyErr_FormatUnraisable(
193+
"Exception ignored while setting error for "
194+
"ctypes callback function %R",
195+
callable);
211196
goto Done;
197+
}
212198
if (flags & FUNCFLAG_USE_ERRNO) {
213199
int temp = space[0];
214200
space[0] = errno;
@@ -295,6 +281,14 @@ static void _CallPythonObject(ctypes_state *st,
295281
for (j = 0; j < i; j++) {
296282
Py_DECREF(args[j]);
297283
}
284+
return;
285+
286+
Error:
287+
PyErr_FormatUnraisable(
288+
"Exception ignored while creating argument %zd for "
289+
"ctypes callback function %R",
290+
i, callable);
291+
goto Done;
298292
}
299293

300294
static void closure_fcn(ffi_cif *cif,

0 commit comments

Comments
 (0)
0