diff --git a/src/ccall.cpp b/src/ccall.cpp index 2c694f60d9c32..0a9db2ca1d5a8 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -111,7 +111,8 @@ static bool runtime_sym_gvs(const char *f_lib, const char *f_name, MT &&M, llvmgv = new GlobalVariable(*M, T_pvoidfunc, false, GlobalVariable::ExternalLinkage, NULL, name); llvmgv = global_proto(llvmgv); - void *addr = jl_dlsym_e(libsym, f_name); + void *addr; + jl_dlsym(libsym, f_name, &addr, 0); (*symMap)[f_name] = std::make_pair(llvmgv, addr); if (symaddr) *symaddr = addr; @@ -776,8 +777,8 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg res = ctx.builder.CreatePtrToInt(res, lrt); } else { - void *symaddr = jl_dlsym_e(jl_get_library(sym.f_lib), sym.f_name); - if (symaddr == NULL) { + void *symaddr; + if (!jl_dlsym(jl_get_library(sym.f_lib), sym.f_name, &symaddr, 0)) { std::stringstream msg; msg << "cglobal: could not find symbol "; msg << sym.f_name; @@ -1490,14 +1491,19 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) }; #define is_libjulia_func(name) _is_libjulia_func((uintptr_t)&(name), #name) + static jl_ptls_t (*ptls_getter)(void) = [] { + // directly accessing the address of an ifunc can cause compile-time linker issues + // on some configurations (e.g. AArch64 + -Bsymbolic-functions), so we guard the + // `&jl_get_ptls_states` within this `#ifdef` guard, and use a more roundabout + // method involving `jl_dlsym()` on Linux platforms instead. #ifdef _OS_LINUX_ - // directly accessing the address of an ifunc can cause linker issue on - // some configurations (e.g. AArch64 + -Bsymbolic-functions). - static const auto ptls_getter = jl_dlsym_e(jl_dlopen(nullptr, 0), - "jl_get_ptls_states"); + jl_ptls_t (*p)(void); + jl_dlsym(jl_dlopen(nullptr, 0), "jl_get_ptls_states", (void **)&p, 0); + return p; #else - static const auto ptls_getter = &jl_get_ptls_states; + return &jl_get_ptls_states; #endif + }(); // emit arguments jl_cgval_t *argv = (jl_cgval_t*)alloca(sizeof(jl_cgval_t) * nccallargs); @@ -1967,8 +1973,8 @@ jl_cgval_t function_sig_t::emit_a_ccall( llvmf = emit_plt(ctx, functype, attributes, cc, symarg.f_lib, symarg.f_name); } else { - void *symaddr = jl_dlsym_e(jl_get_library(symarg.f_lib), symarg.f_name); - if (symaddr == NULL) { + void *symaddr; + if (!jl_dlsym(jl_get_library(symarg.f_lib), symarg.f_name, &symaddr, 0)) { std::stringstream msg; msg << "ccall: could not find function "; msg << symarg.f_name; diff --git a/src/dlload.c b/src/dlload.c index e3fe5b73636e3..8b48f4445dfe0 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -60,18 +60,18 @@ extern char *julia_bindir; #define JL_RTLD(flags, FLAG) (flags & JL_RTLD_ ## FLAG ? RTLD_ ## FLAG : 0) -static void JL_NORETURN jl_dlerror(const char *fmt, const char *sym) +static const char * jl_dlerror(void) { #ifdef _OS_WINDOWS_ - CHAR reason[256]; + static JL_THREAD_LOCAL CHAR reason[256]; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), reason, sizeof(reason) / sizeof(reason[0]), NULL); + return (const char *)&reason[0]; #else - const char *reason = dlerror(); + return dlerror(); #endif - jl_errorf(fmt, sym, reason); } JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) @@ -117,7 +117,7 @@ JL_DLLEXPORT int jl_dlclose(void *handle) #endif } -static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int throw_err) +JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) { char path[PATHBUF]; int i; @@ -192,56 +192,64 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t } notfound: - if (throw_err) - jl_dlerror("could not load library \"%s\"\n%s", modname); + if (throw_err) { + const char * reason = jl_dlerror(); + jl_errorf("could not load library \"%s\"\n%s", modname, reason); + } return NULL; done: return handle; } -JL_DLLEXPORT void *jl_load_dynamic_library_e(const char *modname, unsigned flags) -{ - return jl_load_dynamic_library_(modname, flags, 0); -} - -JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags) +JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int throw_err) { - return jl_load_dynamic_library_(modname, flags, 1); -} + int symbol_found = 0; -JL_DLLEXPORT void *jl_dlsym_e(void *handle, const char *symbol) -{ + /* First, get the symbol value */ #ifdef _OS_WINDOWS_ - void *ptr = GetProcAddress((HMODULE) handle, symbol); + *value = GetProcAddress((HMODULE) handle, symbol); #else dlerror(); /* Reset error status. */ - void *ptr = dlsym(handle, symbol); + *value = dlsym(handle, symbol); #endif - return ptr; -} -JL_DLLEXPORT void *jl_dlsym(void *handle, const char *symbol) -{ - void *ptr = jl_dlsym_e(handle, symbol); - if (!ptr) - jl_dlerror("could not load symbol \"%s\":\n%s", symbol); - return ptr; + /* 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 we unconditionally call + * jl_dlerror() on POSIX systems, but on Windows systems we only call it + * when we have been returned a NULL symbol.*/ + const char * err = NULL; +#ifdef _OS_WINDOWS_ + symbol_found = *value != NULL; +#else + err = jl_dlerror(); + symbol_found = err == NULL; +#endif + + if (!symbol_found && throw_err) { +#ifdef _OS_WINDOWS_ + err = jl_dlerror(); +#endif + jl_errorf("could not load symbol \"%s\":\n%s", symbol, err); + } + return symbol_found; } #ifdef _OS_WINDOWS_ //Look for symbols in win32 libraries const char *jl_dlfind_win32(const char *f_name) { - if (jl_dlsym_e(jl_exe_handle, f_name)) + void * dummy; + if (jl_dlsym(jl_exe_handle, f_name, &dummy, 0)) return JL_EXE_LIBNAME; - if (jl_dlsym_e(jl_dl_handle, f_name)) + if (jl_dlsym(jl_dl_handle, f_name, &dummy, 0)) return JL_DL_LIBNAME; - if (jl_dlsym_e(jl_kernel32_handle, f_name)) + if (jl_dlsym(jl_kernel32_handle, f_name, &dummy, 0)) return "kernel32"; - if (jl_dlsym_e(jl_ntdll_handle, f_name)) + if (jl_dlsym(jl_ntdll_handle, f_name, &dummy, 0)) return "ntdll"; - if (jl_dlsym_e(jl_crtdll_handle, f_name)) + if (jl_dlsym(jl_crtdll_handle, f_name, &dummy, 0)) #if defined(_MSC_VER) #if _MSC_VER == 1800 return "msvcr120"; @@ -251,7 +259,7 @@ const char *jl_dlfind_win32(const char *f_name) #else return "msvcrt"; #endif - if (jl_dlsym_e(jl_winsock_handle, f_name)) + if (jl_dlsym(jl_winsock_handle, f_name, &dummy, 0)) return "ws2_32"; // additional common libraries (libc?) could be added here, but in general, // it is better to specify the library explicitly in the code. This exists diff --git a/src/init.c b/src/init.c index 51ae861473f24..5bfd0fbf3d48b 100644 --- a/src/init.c +++ b/src/init.c @@ -643,7 +643,7 @@ void _julia_init(JL_IMAGE_SEARCH rel) } jl_arr_xtralloc_limit = total_mem / 100; // Extra allocation limited to 1% of total RAM jl_find_stack_bottom(); - jl_dl_handle = jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT); + jl_dl_handle = jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT, 1); #ifdef _OS_WINDOWS_ jl_ntdll_handle = jl_dlopen("ntdll.dll", 0); // bypass julia's pathchecking for system dlls jl_kernel32_handle = jl_dlopen("kernel32.dll", 0); @@ -661,7 +661,7 @@ void _julia_init(JL_IMAGE_SEARCH rel) needsSymRefreshModuleList = 0; HMODULE jl_dbghelp = (HMODULE) jl_dlopen("dbghelp.dll", 0); if (jl_dbghelp) - hSymRefreshModuleList = (BOOL (WINAPI*)(HANDLE)) jl_dlsym(jl_dbghelp, "SymRefreshModuleList"); + jl_dlsym(jl_dbghelp, "SymRefreshModuleList", (void **)&hSymRefreshModuleList, 1); #else jl_exe_handle = jl_dlopen(NULL, JL_RTLD_NOW); #ifdef RTLD_DEFAULT diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index f47a2d28a001b..f21994c2707a0 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -247,14 +247,16 @@ static uint64_t resolve_atomic(const char *name) #elif defined(_OS_WINDOWS_) static const char *const libatomic = "libatomic-1.dll"; #endif - static void *atomic_hdl = jl_load_dynamic_library_e(libatomic, - JL_RTLD_LOCAL); + static void *atomic_hdl = jl_load_dynamic_library(libatomic, + JL_RTLD_LOCAL, 0); static const char *const atomic_prefix = "__atomic_"; if (!atomic_hdl) return 0; if (strncmp(name, atomic_prefix, strlen(atomic_prefix)) != 0) return 0; - return (uintptr_t)jl_dlsym_e(atomic_hdl, name); + uintptr_t value; + jl_dlsym(atomic_hdl, name, (void **)&value, 0); + return value; } #endif diff --git a/src/jlapi.c b/src/jlapi.c index e6d75801e21e4..f88e6fd21a28d 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -58,7 +58,7 @@ JL_DLLEXPORT void jl_init(void) { char *libbindir = NULL; #ifdef _OS_WINDOWS_ - void *hdl = (void*)jl_load_dynamic_library_e(NULL, JL_RTLD_DEFAULT); + void *hdl = (void*)jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT, 0); if (hdl) { char *to_free = (char*)jl_pathname_for_handle(hdl); if (to_free) { diff --git a/src/julia.h b/src/julia.h index 009d3c6ba373f..97951e4ceba92 100644 --- a/src/julia.h +++ b/src/julia.h @@ -45,6 +45,7 @@ # define JL_CONST_FUNC __attribute__((const)) # define JL_USED_FUNC __attribute__((used)) # define JL_SECTION(name) __attribute__((section(name))) +# define JL_THREAD_LOCAL __thread #elif defined(_COMPILER_MICROSOFT_) # define JL_NORETURN __declspec(noreturn) // This is the closest I can find for __attribute__((const)) @@ -53,10 +54,12 @@ # define JL_USED_FUNC // TODO: Figure out what to do on MSVC # define JL_SECTION(x) +# define JL_THREAD_LOCAL __declspec(threaD) #else # define JL_NORETURN # define JL_CONST_FUNC # define JL_USED_FUNC +# define JL_THREAD_LOCAL #endif #define container_of(ptr, type, member) \ @@ -1498,12 +1501,10 @@ enum JL_RTLD_CONSTANT { #define JL_RTLD_DEFAULT (JL_RTLD_LAZY | JL_RTLD_DEEPBIND) typedef void *jl_uv_libhandle; // compatible with dlopen (void*) / LoadLibrary (HMODULE) -JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned flags); -JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library_e(const char *fname, unsigned flags); +JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned flags, int throw_err); JL_DLLEXPORT jl_uv_libhandle jl_dlopen(const char *filename, unsigned flags); JL_DLLEXPORT int jl_dlclose(jl_uv_libhandle handle); -JL_DLLEXPORT void *jl_dlsym_e(jl_uv_libhandle handle, const char *symbol); -JL_DLLEXPORT void *jl_dlsym(jl_uv_libhandle handle, const char *symbol); +JL_DLLEXPORT int jl_dlsym(jl_uv_libhandle handle, const char *symbol, void ** value, int throw_err); // compiler JL_DLLEXPORT jl_value_t *jl_toplevel_eval(jl_module_t *m, jl_value_t *v); diff --git a/src/processor.cpp b/src/processor.cpp index 497f4b976c9eb..0915adbc3e8d1 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -621,23 +621,33 @@ template static inline jl_sysimg_fptrs_t parse_sysimg(void *hdl, F &&callback) { jl_sysimg_fptrs_t res = {nullptr, 0, nullptr, 0, nullptr, nullptr}; + char * data_base; + // .data base - auto data_base = (char*)jl_dlsym(hdl, "jl_sysimg_gvars_base"); + jl_dlsym(hdl, "jl_sysimg_gvars_base", (void **)&data_base, 1); // .text base - res.base = (const char*)jl_dlsym(hdl, "jl_sysimg_fvars_base"); - auto offsets = ((const int32_t*)jl_dlsym(hdl, "jl_sysimg_fvars_offsets")) + 1; - uint32_t nfunc = ((const uint32_t*)offsets)[-1]; - res.offsets = offsets; + jl_dlsym(hdl, "jl_sysimg_fvars_base", (void **)&res.base, 1); + + const int32_t * offsets; + jl_dlsym(hdl, "jl_sysimg_fvars_offsets", (void **)&offsets, 1); + uint32_t nfunc = offsets[0]; + res.offsets = offsets + 1; - void *ids = jl_dlsym(hdl, "jl_dispatch_target_ids"); + void *ids; + jl_dlsym(hdl, "jl_dispatch_target_ids", &ids, 1); uint32_t target_idx = callback(ids); - auto reloc_slots = ((const int32_t*)jl_dlsym(hdl, "jl_dispatch_reloc_slots")) + 1; - auto nreloc = ((const uint32_t*)reloc_slots)[-1]; - auto clone_idxs = (const uint32_t*)jl_dlsym(hdl, "jl_dispatch_fvars_idxs"); - auto clone_offsets = (const int32_t*)jl_dlsym(hdl, "jl_dispatch_fvars_offsets"); + const int32_t * reloc_slots; + jl_dlsym(hdl, "jl_dispatch_reloc_slots",(void **) &reloc_slots, 1); + const uint32_t nreloc = reloc_slots[0]; + reloc_slots += 1; + const uint32_t * clone_idxs; + const int32_t * clone_offsets; + jl_dlsym(hdl, "jl_dispatch_fvars_idxs", (void **)&clone_idxs, 1); + jl_dlsym(hdl, "jl_dispatch_fvars_offsets", (void **)&clone_offsets, 1); uint32_t tag_len = clone_idxs[0]; clone_idxs += 1; + assert(tag_len & jl_sysimg_tag_mask); std::vector base_offsets = {res.offsets}; // Find target diff --git a/src/processor_arm.cpp b/src/processor_arm.cpp index 6b96c93898b1b..000894fb05d7d 100644 --- a/src/processor_arm.cpp +++ b/src/processor_arm.cpp @@ -499,17 +499,6 @@ static constexpr size_t ncpu_names = sizeof(cpus) / sizeof(cpus[0]); #endif #if defined(DYN_GETAUXVAL) -static bool getauxval_dlsym(unsigned long type, unsigned long *val) -{ - static auto getauxval_p = (unsigned long (*)(unsigned long)) - jl_dlsym_e(jl_dlopen(nullptr, JL_RTLD_LOCAL), "getauxval"); - if (getauxval_p) { - *val = getauxval_p(type); - return true; - } - return false; -} - static unsigned long getauxval_procfs(unsigned long type) { int fd = open("/proc/self/auxv", O_RDONLY); @@ -531,9 +520,14 @@ static unsigned long getauxval_procfs(unsigned long type) static inline unsigned long jl_getauxval(unsigned long type) { - unsigned long val; - if (getauxval_dlsym(type, &val)) - return val; + // First, try resolving getauxval in libc + auto libc = jl_dlopen(nullptr, JL_RTLD_LOCAL); + static (unsigned long (*)(unsigned long) getauxval_p; + if (jl_dlsym(libc, "getauxval", &getauxval_p, 0) { + return getauxval_p(type); + } + + // If we couldn't resolve it, use procfs. return getauxval_procfs(type); } #else diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index 2187fc9ccea06..47bb1486f5822 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -45,7 +45,7 @@ void *jl_get_library(const char *f_lib) if (hnd != NULL) return hnd; // We might run this concurrently on two threads but it doesn't matter. - hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT); + hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT, 1); if (hnd != NULL) jl_atomic_store_release(map_slot, hnd); return hnd; @@ -57,7 +57,9 @@ void *jl_load_and_lookup(const char *f_lib, const char *f_name, void **hnd) void *handle = jl_atomic_load_acquire(hnd); if (!handle) jl_atomic_store_release(hnd, (handle = jl_get_library(f_lib))); - return jl_dlsym(handle, f_name); + void * ptr; + jl_dlsym(handle, f_name, &ptr, 1); + return ptr; } // miscellany diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index eece1a1f9cc38..f947f22b3adf3 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -121,7 +121,8 @@ JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) f_lib = (char*)jl_dlfind_win32(f_name); #endif - void *ptr = jl_dlsym(jl_get_library(f_lib), f_name); + void *ptr; + jl_dlsym(jl_get_library(f_lib), f_name, &ptr, 1); jl_value_t *jv = jl_gc_alloc_1w(); jl_set_typeof(jv, rt); *(void**)jl_data_ptr(jv) = ptr; diff --git a/src/signals-win.c b/src/signals-win.c index 0672da59a17cb..264c197e41c40 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -102,8 +102,7 @@ void restore_signals(void) // turn on ctrl-c handler SetConsoleCtrlHandler(NULL, 0); // see if SetThreadStackGuarantee exists - pSetThreadStackGuarantee = (BOOL (*)(PULONG)) jl_dlsym_e(jl_kernel32_handle, - "SetThreadStackGuarantee"); + jl_dlsym(jl_kernel32_handle, "SetThreadStackGuarantee", (const void **)&pSetThreadStackGuarantee, 0); } void jl_throw_in_ctx(jl_value_t *excpt, CONTEXT *ctxThread, int bt) diff --git a/src/staticdata.c b/src/staticdata.c index 340f76811d73b..b86ac914a7a57 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -165,17 +165,17 @@ static void jl_load_sysimg_so(void) int imaging_mode = jl_generating_output() && !jl_options.incremental; // in --build mode only use sysimg data, not precompiled native code if (!imaging_mode && jl_options.use_sysimage_native_code==JL_OPTIONS_USE_SYSIMAGE_NATIVE_CODE_YES) { - sysimg_gvars_base = (uintptr_t*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_base"); - sysimg_gvars_offsets = (const int32_t*)jl_dlsym(jl_sysimg_handle, - "jl_sysimg_gvars_offsets"); + jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_base", (void **)&sysimg_gvars_base, 1); + jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_offsets", (void **)&sysimg_gvars_offsets, 1); sysimg_gvars_offsets += 1; assert(sysimg_fptrs.base); - globalUnique = *(size_t*)jl_dlsym(jl_sysimg_handle, "jl_globalUnique"); + jl_dlsym(jl_sysimg_handle, "jl_globalUnique", (void **)&globalUnique, 1); #ifdef JULIA_ENABLE_THREADING - uintptr_t *tls_getter_slot = (uintptr_t*)jl_dlsym(jl_sysimg_handle, - "jl_get_ptls_states_slot"); + uintptr_t *tls_getter_slot; + jl_dlsym(jl_sysimg_handle, "jl_get_ptls_states_slot", (void **)&tls_getter_slot, 1); *tls_getter_slot = (uintptr_t)jl_get_ptls_states_getter(); - size_t *tls_offset_idx = (size_t*)jl_dlsym(jl_sysimg_handle, "jl_tls_offset"); + size_t *tls_offset_idx; + jl_dlsym(jl_sysimg_handle, "jl_tls_offset", (void **)&tls_offset_idx, 1); *tls_offset_idx = (uintptr_t)(jl_tls_offset == -1 ? 0 : jl_tls_offset); #endif @@ -194,8 +194,10 @@ static void jl_load_sysimg_so(void) else { memset(&sysimg_fptrs, 0, sizeof(sysimg_fptrs)); } - const char *sysimg_data = (const char*)jl_dlsym(jl_sysimg_handle, "jl_system_image_data"); - size_t len = *(size_t*)jl_dlsym(jl_sysimg_handle, "jl_system_image_size"); + const char *sysimg_data; + jl_dlsym(jl_sysimg_handle, "jl_system_image_data", (void **)&sysimg_data, 1); + size_t len; + jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&len, 1); jl_restore_system_image_data(sysimg_data, len); } @@ -1406,14 +1408,15 @@ JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname) // Get handle to sys.so if (!is_ji) // .ji extension => load .ji file only - jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW)); + jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW, 1)); } // Allow passing in a module handle directly, rather than a path JL_DLLEXPORT void jl_set_sysimg_so(void *handle) { - void* *jl_RTLD_DEFAULT_handle_pointer = (void**)jl_dlsym_e(handle, "jl_RTLD_DEFAULT_handle_pointer"); - if (!jl_RTLD_DEFAULT_handle_pointer || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer) + void* *jl_RTLD_DEFAULT_handle_pointer; + int symbol_found = jl_dlsym(handle, "jl_RTLD_DEFAULT_handle_pointer", (void **)&jl_RTLD_DEFAULT_handle_pointer, 0); + if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer) jl_error("System image file failed consistency check: maybe opened the wrong version?"); if (jl_options.cpu_target == NULL) jl_options.cpu_target = "native"; diff --git a/src/support/dirname.c b/src/support/dirname.c index 520055df28bcb..e023b842ce13d 100644 --- a/src/support/dirname.c +++ b/src/support/dirname.c @@ -42,11 +42,7 @@ extern "C" { JL_DLLEXPORT char *dirname( char *path ) { size_t len; -# if !defined(_COMPILER_MICROSOFT_) - static __thread char *retfail = NULL; -# else - static __declspec(thread) char *retfail = NULL; -# endif + static JL_THREAD_LOCAL char *retfail = NULL; /* to handle path names for files in multibyte character locales, * we need to set up LC_CTYPE to match the host file system locale. diff --git a/src/sys.c b/src/sys.c index 9333ac2a74d00..cfce86916d629 100644 --- a/src/sys.c +++ b/src/sys.c @@ -382,12 +382,8 @@ JL_DLLEXPORT int jl_cpu_threads(void) return count; #elif defined(_OS_WINDOWS_) //Try to get WIN7 API method - GAPC gapc = (GAPC) jl_dlsym_e( - jl_kernel32_handle, - "GetActiveProcessorCount" - ); - - if (gapc) { + GAPC gapc; + if (jl_dlsym(jl_kernel32_handle, "GetActiveProcessorCount", (void **)&gapc, 0)) { return gapc(ALL_PROCESSOR_GROUPS); } else { //fall back on GetSystemInfo @@ -538,7 +534,7 @@ JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle) for (int32_t i = _dyld_image_count() - 1; i >= 0 ; i--) { // dlopen() each image, check handle const char *image_name = _dyld_get_image_name(i); - void *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT); + void *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT, 0); jl_dlclose(probe_lib); // If the handle is the same as what was passed in (modulo mode bits), return this image name diff --git a/stdlib/Libdl/src/Libdl.jl b/stdlib/Libdl/src/Libdl.jl index 3a7dbd7fe019c..f0e7d9f174256 100644 --- a/stdlib/Libdl/src/Libdl.jl +++ b/stdlib/Libdl/src/Libdl.jl @@ -50,19 +50,26 @@ applicable. Look up a symbol from a shared library handle, return callable function pointer on success. """ -function dlsym(hnd::Ptr, s::Union{Symbol,AbstractString}) +function dlsym(hnd::Ptr, s::Union{Symbol,AbstractString}; throw_error::Bool = true) hnd == C_NULL && throw(ArgumentError("NULL library handle")) - ccall(:jl_dlsym, Ptr{Cvoid}, (Ptr{Cvoid}, Cstring), hnd, s) + val = Ref(Ptr{Cvoid}(0)) + symbol_found = ccall(:jl_dlsym, Cint, + (Ptr{Cvoid}, Cstring, Ref{Ptr{Cvoid}}, Cint), + hnd, s, val, Int64(throw_error) + ) + if symbol_found == 0 + return nothing + end + return val[] end """ dlsym_e(handle, sym) -Look up a symbol from a shared library handle, silently return `NULL` pointer on lookup failure. +Look up a symbol from a shared library handle, silently return `NULL` pointer on lookup failure. It is preferred to use dlsym(handle, sym; throw_error=false). """ function dlsym_e(hnd::Ptr, s::Union{Symbol,AbstractString}) - hnd == C_NULL && throw(ArgumentError("NULL library handle")) - ccall(:jl_dlsym_e, Ptr{Cvoid}, (Ptr{Cvoid}, Cstring), hnd, s) + return dlsym(hnd, s; throw_error=false) end """ @@ -88,27 +95,29 @@ exported symbols and if the bound references are put into process local or globa instance `RTLD_LAZY|RTLD_DEEPBIND|RTLD_GLOBAL` allows the library's symbols to be available for usage in other shared libraries, addressing situations where there are dependencies between shared libraries. + +If the library cannot be found, this method returns `nothing`. """ function dlopen end -dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - dlopen(string(s), flags) +dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; kwargs...) = + dlopen(string(s), flags; kwargs...) -dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - ccall(:jl_load_dynamic_library, Ptr{Cvoid}, (Cstring,UInt32), s, flags) +function dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; throw_error::Bool = true) + ret = ccall(:jl_load_dynamic_library, Ptr{Cvoid}, (Cstring,UInt32,Cint), s, flags, Cint(throw_error)) + if ret == C_NULL + return nothing + end + return ret +end """ dlopen_e(libfile::AbstractString [, flags::Integer]) Similar to [`dlopen`](@ref), except returns a `NULL` pointer instead of raising errors. +It is preferred to directly call dlopen(libfile, flags; throw_error=false)` """ -function dlopen_e end - -dlopen_e(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - dlopen_e(string(s), flags) - -dlopen_e(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - ccall(:jl_load_dynamic_library_e, Ptr{Cvoid}, (Cstring,UInt32), s, flags) +dlopen_e(args...) = dlopen(args...; throw_error=false) """ dlclose(handle) @@ -119,6 +128,25 @@ function dlclose(p::Ptr) 0 == ccall(:jl_dlclose, Cint, (Ptr{Cvoid},), p) end +""" + dlclose(::Nothing) + +For the very common pattern usage pattern of + + try + hdl = dlopen(library_name) + ... do something + finally + dlclose(hdl) + end + +We define a `dlclose()` method that accepts a parameter of type `Nothing`, so +that user code does not have to change its behavior for the case that `library_name` +was not found. +""" +function dlclose(p::Nothing) +end + """ find_library(names, locations) @@ -132,14 +160,14 @@ function find_library(libnames, extrapaths=String[]) for lib in libnames for path in extrapaths l = joinpath(path, lib) - p = dlopen_e(l, RTLD_LAZY) - if p != C_NULL + p = dlopen(l, RTLD_LAZY; throw_error=false) + if p !== nothing dlclose(p) return l end end - p = dlopen_e(lib, RTLD_LAZY) - if p != C_NULL + p = dlopen(lib, RTLD_LAZY; throw_error=false) + if p !== nothing dlclose(p) return lib end diff --git a/stdlib/Libdl/test/runtests.jl b/stdlib/Libdl/test/runtests.jl index 74b541e1dc5e6..c3266772888a6 100644 --- a/stdlib/Libdl/test/runtests.jl +++ b/stdlib/Libdl/test/runtests.jl @@ -10,7 +10,7 @@ dlls = Libdl.dllist() @test length(dlls) > 3 # at a bare minimum, probably have some version of libstdc, libgcc, libjulia, ... if !Sys.iswindows() || Sys.windows_version() >= Sys.WINDOWS_VISTA_VER for dl in dlls - if isfile(dl) && (Libdl.dlopen_e(dl) != C_NULL) + if isfile(dl) && (Libdl.dlopen(dl; throw_error=false) != C_NULL) @test Base.samefile(Libdl.dlpath(dl), dl) end end @@ -45,8 +45,8 @@ end # dlopen should be able to handle absolute and relative paths, with and without dlext let dl = C_NULL try - dl = Libdl.dlopen_e(abspath(joinpath(private_libdir, "libccalltest"))) - @test dl != C_NULL + dl = Libdl.dlopen(abspath(joinpath(private_libdir, "libccalltest")); throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -54,8 +54,8 @@ end let dl = C_NULL try - dl = Libdl.dlopen_e(abspath(joinpath(private_libdir, "libccalltest.$(Libdl.dlext)"))) - @test dl != C_NULL + dl = Libdl.dlopen(abspath(joinpath(private_libdir, "libccalltest.$(Libdl.dlext)")); throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -63,8 +63,8 @@ end let dl = C_NULL try - dl = Libdl.dlopen_e(relpath(joinpath(private_libdir, "libccalltest"))) - @test dl != C_NULL + dl = Libdl.dlopen(relpath(joinpath(private_libdir, "libccalltest")); throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -72,8 +72,8 @@ end let dl = C_NULL try - dl = Libdl.dlopen_e(relpath(joinpath(private_libdir, "libccalltest.$(Libdl.dlext)"))) - @test dl != C_NULL + dl = Libdl.dlopen(relpath(joinpath(private_libdir, "libccalltest.$(Libdl.dlext)")); throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -81,8 +81,8 @@ end let dl = C_NULL try - dl = Libdl.dlopen_e("./foo") - @test dl == C_NULL + dl = Libdl.dlopen("./foo"; throw_error=false) + @test dl === nothing finally Libdl.dlclose(dl) end @@ -91,8 +91,8 @@ end # unqualified names present in DL_LOAD_PATH let dl = C_NULL try - dl = Libdl.dlopen_e("libccalltest") - @test dl != C_NULL + dl = Libdl.dlopen("libccalltest"; throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -100,8 +100,8 @@ end let dl = C_NULL try - dl = Libdl.dlopen_e(string("libccalltest",".",Libdl.dlext)) - @test dl != C_NULL + dl = Libdl.dlopen(string("libccalltest",".",Libdl.dlext); throw_error=false) + @test dl !== nothing finally Libdl.dlclose(dl) end @@ -149,8 +149,8 @@ end let dl = C_NULL try path = abspath(joinpath(private_libdir, "libccalltest")) - dl = Libdl.dlopen(path) - @test dl != C_NULL + dl = Libdl.dlopen(path; throw_error=false) + @test dl !== nothing @test Base.samefile(abspath(Libdl.dlpath(dl)), abspath(Libdl.dlpath(path))) @test Base.samefile(abspath(Libdl.dlpath(dl)), @@ -174,13 +174,13 @@ let dl = C_NULL try dl = Libdl.dlopen(abspath(joinpath(private_libdir, "libccalltest"))) fptr = Libdl.dlsym(dl, :set_verbose) - @test fptr != C_NULL + @test fptr !== nothing @test_throws ErrorException Libdl.dlsym(dl, :foo) fptr = Libdl.dlsym_e(dl, :set_verbose) - @test fptr != C_NULL + @test fptr !== nothing fptr = Libdl.dlsym_e(dl, :foo) - @test fptr == C_NULL + @test fptr === nothing finally Libdl.dlclose(dl) end @@ -193,8 +193,8 @@ let dl = C_NULL @test -1 == ccall(:jl_dlclose, Cint, (Ptr{Cvoid},), dl) @test !Libdl.dlclose(dl) - dl = Libdl.dlopen_e("libccalltest") - @test dl != C_NULL + dl = Libdl.dlopen("libccalltest"; throw_error=false) + @test dl !== nothing @test Libdl.dlclose(dl) @test_skip !Libdl.dlclose(dl) # Syscall doesn't fail on Win32 diff --git a/stdlib/LinearAlgebra/src/blas.jl b/stdlib/LinearAlgebra/src/blas.jl index 0e711875110e7..fee8c9e74d7ed 100644 --- a/stdlib/LinearAlgebra/src/blas.jl +++ b/stdlib/LinearAlgebra/src/blas.jl @@ -72,14 +72,16 @@ import Libdl # utility routines let lib = C_NULL global function determine_vendor() - lib == C_NULL && (lib = Libdl.dlopen_e(Base.libblas_name)) + if lib == C_NULL + lib = Libdl.dlopen(Base.libblas_name; throw_error=false) + end vend = :unknown if lib != C_NULL - if Libdl.dlsym_e(lib, :openblas_set_num_threads) != C_NULL + if Libdl.dlsym(lib, :openblas_set_num_threads; throw_error=false) !== nothing vend = :openblas - elseif Libdl.dlsym_e(lib, :openblas_set_num_threads64_) != C_NULL + elseif Libdl.dlsym(lib, :openblas_set_num_threads64_; throw_error=false) !== nothing vend = :openblas64 - elseif Libdl.dlsym_e(lib, :MKL_Set_Num_Threads) != C_NULL + elseif Libdl.dlsym(lib, :MKL_Set_Num_Threads; throw_error=false) !== nothing vend = :mkl end end