Skip to content

Commit

Permalink
avoid calling dlerror unless absolutely necessary (#40392)
Browse files Browse the repository at this point in the history
Most platforms implement this sensibly, but POSIX does not require that,
so FreeBSD does not implement this sensibly. But we can mostly avoid the
problems on FreeBSD by avoiding calling it unless we absolutely must.

Fixes #39582
  • Loading branch information
vtjnash authored Apr 8, 2021
1 parent f021c67 commit 5b6edad
Showing 1 changed file with 23 additions and 13 deletions.
36 changes: 23 additions & 13 deletions src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI
needsSymRefreshModuleList = 1;
return lib;
#else
dlerror(); /* Reset error status. */
return dlopen(filename,
(flags & JL_RTLD_NOW ? RTLD_NOW : RTLD_LAZY)
| JL_RTLD(flags, LOCAL)
Expand All @@ -144,11 +143,15 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI
JL_DLLEXPORT int jl_dlclose(void *handle) JL_NOTSAFEPOINT
{
#ifdef _OS_WINDOWS_
if (!handle) return -1;
if (!handle) {
return -1;
}
return !FreeLibrary((HMODULE) handle);
#else
dlerror(); /* Reset error status. */
if (!handle) return -1;
if (!handle) {
dlerror(); /* Reset error status. */
return -1;
}
return dlclose(handle);
#endif
}
Expand Down Expand Up @@ -291,19 +294,26 @@ JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int t
#ifdef _OS_WINDOWS_
*value = GetProcAddress((HMODULE) handle, symbol);
#else
dlerror(); /* Reset error status. */
*value = dlsym(handle, symbol);
#endif

/* Next, check for errors. On Windows, a NULL pointer means the symbol
* was not found. On everything else, we can have NULL symbols, so we check
* for non-NULL returns from dlerror(). Note that means we unconditionally
* call dlerror() on POSIX systems.*/
#ifdef _OS_WINDOWS_
/* Next, check for errors. On Windows, a NULL pointer means the symbol was
* not found. On everything else, we can have NULL symbols, so we check for
* non-NULL returns from dlerror(). Since POSIX doesn't require `dlerror`
* to be implemented safely, FreeBSD doesn't (unlike everyone else, who
* realized decades ago that threads are here to stay), so we avoid calling
* `dlerror` unless we need to get the error message.
* https://github.com/freebsd/freebsd-src/blob/12db51d20823a5e3b9e5f8a2ea73156fe1cbfc28/libexec/rtld-elf/rtld.c#L198
*/
symbol_found = *value != NULL;
#else
const char *err = dlerror();
symbol_found = err == NULL;
#ifndef _OS_WINDOWS_
const char *err;
if (!symbol_found) {
dlerror(); /* Reset error status. */
*value = dlsym(handle, symbol);
err = dlerror();
symbol_found = *value != NULL || err == NULL;
}
#endif

if (!symbol_found && throw_err) {
Expand Down

0 comments on commit 5b6edad

Please sign in to comment.