From 5b6edad71900b3a2a206a0583953eceaa06a2f89 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 8 Apr 2021 15:43:01 -0400 Subject: [PATCH] avoid calling dlerror unless absolutely necessary (#40392) 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 --- src/dlload.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/dlload.c b/src/dlload.c index ecb34d2be57e3..62f28d583a85a 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -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) @@ -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 } @@ -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) {