Skip to content

Commit 3c3c29d

Browse files
committed
ctypes: Correctly handle NULL dlsym values
For dlsym(), a return value of NULL does not necessarily indicate an error [1]. Therefore, to avoid using stale (or NULL) dlerror() values, we must: 1. clear the previous error state by calling dlerror() 2. call dlsym() 3. call dlerror() If the return value of dlerror() is not NULL, an error occured. In our case, we also subjectively treat a NULL return value from dlsym() as an error, so we format a special string for that. [1]: https://man7.org/linux/man-pages/man3/dlsym.3.html Signed-off-by: Georgios Alexopoulos <[email protected]>
1 parent 09d6f5d commit 3c3c29d

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Correctly handle NULL dlsym() values in ctypes.

Modules/_ctypes/_ctypes.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -967,18 +967,30 @@ CDataType_in_dll_impl(PyObject *type, PyTypeObject *cls, PyObject *dll,
967967
return NULL;
968968
}
969969
#else
970+
dlerror();
970971
address = (void *)dlsym(handle, name);
971-
if (!address) {
972972
#ifdef __CYGWIN__
973-
/* dlerror() isn't very helpful on cygwin */
973+
if (!address) {
974+
/* dlerror() isn't very helpful on cygwin */
974975
PyErr_Format(PyExc_ValueError,
975976
"symbol '%s' not found",
976977
name);
978+
return NULL;
979+
}
977980
#else
978-
PyErr_SetString(PyExc_ValueError, dlerror());
979-
#endif
981+
char *dlerr;
982+
dlerr = dlerror();
983+
if (dlerr) {
984+
PyErr_SetString(PyExc_ValueError, dlerr);
985+
return NULL;
986+
}
987+
else if (!address) {
988+
PyErr_Format(PyExc_ValueError,
989+
"symbol '%s' not found",
990+
name);
980991
return NULL;
981992
}
993+
#endif
982994
#endif
983995
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
984996
return PyCData_AtAddress(st, type, address);
@@ -3774,19 +3786,33 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
37743786
return NULL;
37753787
}
37763788
#else
3789+
dlerror();
37773790
address = (PPROC)dlsym(handle, name);
3778-
if (!address) {
37793791
#ifdef __CYGWIN__
3780-
/* dlerror() isn't very helpful on cygwin */
3792+
if (!address) {
3793+
/* dlerror() isn't very helpful on cygwin */
37813794
PyErr_Format(PyExc_AttributeError,
37823795
"function '%s' not found",
37833796
name);
3797+
Py_DECREF(ftuple);
3798+
return NULL;
3799+
}
37843800
#else
3785-
PyErr_SetString(PyExc_AttributeError, dlerror());
3786-
#endif
3801+
char *dlerr;
3802+
dlerr = dlerror();
3803+
if (dlerr) {
3804+
PyErr_SetString(PyExc_AttributeError, dlerr);
3805+
Py_DECREF(ftuple);
3806+
return NULL;
3807+
}
3808+
else if (!address) {
3809+
PyErr_Format(PyExc_AttributeError,
3810+
"function '%s' not found",
3811+
name);
37873812
Py_DECREF(ftuple);
37883813
return NULL;
37893814
}
3815+
#endif
37903816
#endif
37913817
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
37923818
if (!_validate_paramflags(st, type, paramflags)) {

0 commit comments

Comments
 (0)