Bug report
Bug description:
The man(3) page for dlsym() states:
In unusual cases (see NOTES) the value of the symbol could actually be
NULL. Therefore, a NULL return from dlsym() need not indicate an error.
The correct way to distinguish an error from a symbol whose value is NULL
is to call dlerror(3) to clear any old error conditions, then call dl‐
sym(), and then call dlerror(3) again, saving its return value into a
variable, and check whether this saved value is not NULL.
As such, there can be cases where a call to dlsym returns NULL, while no error has been encountered and the string that dlerror() returns has not been (re)set.
Currently, (https://github.com/python/cpython/blob/main/Modules/_ctypes/_ctypes.c#L970) we do:
<...>
address = (void *)dlsym(handle, name);
if (!address) {
#ifdef __CYGWIN__
<snip Windows stuff>
#else
PyErr_SetString(PyExc_ValueError, dlerror());
<...>
If dlsym() returns NULL, then by calling dlerror() we pass either NULL or a previous, unconsumed error string to PyErr_SetString.
In the context of ctypes, a NULL return by dlsym() might indeed always be considered an error.
To correctly express this, we should:
- Call
dlerror() before dlsym(), to clear any previous error
- Call
dlerror() after dlsym(), to see if dlsym() encountered any error
- If
dlerror() returns a non-NULL value, then pass its result to PyErr_SetString
- If
dlerror() returns NULL, then check if address is NULL, and if so, pass a custom error string to PyErr_SetString.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Bug report
Bug description:
The man(3) page for
dlsym()states:As such, there can be cases where a call to
dlsymreturnsNULL, while no error has been encountered and the string thatdlerror()returns has not been (re)set.Currently, (https://github.com/python/cpython/blob/main/Modules/_ctypes/_ctypes.c#L970) we do:
If
dlsym()returnsNULL, then by callingdlerror()we pass eitherNULLor a previous, unconsumed error string toPyErr_SetString.In the context of
ctypes, aNULLreturn bydlsym()might indeed always be considered an error.To correctly express this, we should:
dlerror()beforedlsym(), to clear any previous errordlerror()afterdlsym(), to see ifdlsym()encountered any errordlerror()returns a non-NULL value, then pass its result toPyErr_SetStringdlerror()returns NULL, then check ifaddressis NULL, and if so, pass a custom error string toPyErr_SetString.CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
gccforTestNullDlsym.test_null_dlsym#129872gccforTestNullDlsym.test_null_dlsym(GH-129872) #129944gccforTestNullDlsym.test_null_dlsym(GH-129872) #129945