Skip to content

Commit

Permalink
Rework Libdl.dlsym() and jl_dlsym().
Browse files Browse the repository at this point in the history
* Remove `jl_dlsym_e()` to instead be rolled into `jl_dlsym()` with a `throw_err` parameter, similar to `jl_load_dynamic_library()`.

* Fix JuliaLang#28881 by having `Libdl.dlsym()` return `nothing` on missing symbol, rather than `C_NULL`.
  • Loading branch information
staticfloat committed Aug 29, 2018
1 parent 255030e commit 68cc9f0
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 92 deletions.
17 changes: 8 additions & 9 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1490,13 +1491,11 @@ 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 auto ptls_getter = &jl_get_ptls_states;
#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");
#else
static const auto ptls_getter = &jl_get_ptls_states;
jl_dlsym(jl_dlopen(nullptr, 0), "jl_get_ptls_states", (void **)&ptls_getter, 0);
#endif

// emit arguments
Expand Down Expand Up @@ -1967,8 +1966,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;
Expand Down
64 changes: 41 additions & 23 deletions src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)
Expand Down Expand Up @@ -192,8 +192,10 @@ 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:
Expand All @@ -210,38 +212,54 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags)
return jl_load_dynamic_library_(modname, flags, 1);
}

JL_DLLEXPORT void *jl_dlsym_e(void *handle, const char *symbol)
JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int throw_err)
{
int symbol_found = 0;

/* 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";
Expand All @@ -251,7 +269,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
Expand Down
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ static uint64_t resolve_atomic(const char *name)
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

Expand Down
3 changes: 1 addition & 2 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1502,8 +1502,7 @@ JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned
JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library_e(const char *fname, unsigned flags);
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);
Expand Down
30 changes: 20 additions & 10 deletions src/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,23 +621,33 @@ template<typename F>
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<const int32_t*> base_offsets = {res.offsets};
// Find target
Expand Down
22 changes: 8 additions & 14 deletions src/processor_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/runtime_ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/runtime_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/signals-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 14 additions & 11 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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);
}

Expand Down Expand Up @@ -1412,8 +1414,9 @@ JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname)
// 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";
Expand Down
8 changes: 2 additions & 6 deletions src/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 68cc9f0

Please sign in to comment.