Skip to content

Commit bc3ce76

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 bc3ce76

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
@@ -934,6 +934,7 @@ CDataType_in_dll_impl(PyObject *type, PyTypeObject *cls, PyObject *dll,
934934
PyObject *obj;
935935
void *handle;
936936
void *address;
937+
char *dlerr;
937938

938939
if (PySys_Audit("ctypes.dlsym", "Os", dll, name) < 0) {
939940
return NULL;
@@ -967,18 +968,29 @@ CDataType_in_dll_impl(PyObject *type, PyTypeObject *cls, PyObject *dll,
967968
return NULL;
968969
}
969970
#else
971+
dlerror();
970972
address = (void *)dlsym(handle, name);
971-
if (!address) {
972973
#ifdef __CYGWIN__
973-
/* dlerror() isn't very helpful on cygwin */
974+
if (!address) {
975+
/* dlerror() isn't very helpful on cygwin */
974976
PyErr_Format(PyExc_ValueError,
975977
"symbol '%s' not found",
976978
name);
979+
return NULL;
980+
}
977981
#else
978-
PyErr_SetString(PyExc_ValueError, dlerror());
979-
#endif
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);
@@ -3706,6 +3718,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
37063718
PyCFuncPtrObject *self;
37073719
void *handle;
37083720
PyObject *paramflags = NULL;
3721+
char *dlerr;
37093722

37103723
if (!PyArg_ParseTuple(args, "O|O", &ftuple, &paramflags))
37113724
return NULL;
@@ -3774,19 +3787,32 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
37743787
return NULL;
37753788
}
37763789
#else
3790+
dlerror();
37773791
address = (PPROC)dlsym(handle, name);
3778-
if (!address) {
37793792
#ifdef __CYGWIN__
3780-
/* dlerror() isn't very helpful on cygwin */
3793+
if (!address) {
3794+
/* dlerror() isn't very helpful on cygwin */
37813795
PyErr_Format(PyExc_AttributeError,
37823796
"function '%s' not found",
37833797
name);
3798+
Py_DECREF(ftuple);
3799+
return NULL;
3800+
}
37843801
#else
3785-
PyErr_SetString(PyExc_AttributeError, dlerror());
3786-
#endif
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)