Skip to content

Commit

Permalink
make dlopen more conservative about opening files the user didn't req…
Browse files Browse the repository at this point in the history
…uest (#18061)

* make dlopen more conservative about opening files the user didn't request

* update manual

* recognize \server\foo and /foo/bar absolute paths on windows, similar to isabspath

* simplify isabspath from init.c and use it in dlopen instead of duplicating
  • Loading branch information
stevengj authored Aug 18, 2016
1 parent adecd73 commit b506041
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 44 deletions.
6 changes: 6 additions & 0 deletions base/libdl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ end
Load a shared library, returning an opaque handle.
The extension given by the constant `dlext` (`.so`, `.dll`, or `.dylib`)
can be omitted from the `libfile` string, as it is automatically appended
if needed. If `libfile` is not an absolute path name, then the paths
in the array `DL_LOAD_PATH` are searched for `libfile`, followed by the
system load path.
The optional flags argument is a bitwise-or of zero or more of `RTLD_LOCAL`, `RTLD_GLOBAL`,
`RTLD_LAZY`, `RTLD_NOW`, `RTLD_NODELETE`, `RTLD_NOLOAD`, `RTLD_DEEPBIND`, and `RTLD_FIRST`.
These are converted to the corresponding flags of the POSIX (and/or GNU libc and/or MacOS)
Expand Down
2 changes: 2 additions & 0 deletions doc/stdlib/libdl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ The names in :mod:`Base.Libdl` are not exported and need to be called e.g. as ``
Load a shared library, returning an opaque handle.

The extension given by the constant ``dlext`` (``.so``\ , ``.dll``\ , or ``.dylib``\ ) can be omitted from the ``libfile`` string, as it is automatically appended if needed. If ``libfile`` is not an absolute path name, then the paths in the array ``DL_LOAD_PATH`` are searched for ``libfile``\ , followed by the system load path.

The optional flags argument is a bitwise-or of zero or more of ``RTLD_LOCAL``\ , ``RTLD_GLOBAL``\ , ``RTLD_LAZY``\ , ``RTLD_NOW``\ , ``RTLD_NODELETE``\ , ``RTLD_NOLOAD``\ , ``RTLD_DEEPBIND``\ , and ``RTLD_FIRST``\ . These are converted to the corresponding flags of the POSIX (and/or GNU libc and/or MacOS) dlopen command, if possible, or are ignored if the specified functionality is not available on the current platform. The default flags are platform specific. On MacOS the default ``dlopen`` flags are ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_GLOBAL`` while on other platforms the defaults are ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_LOCAL``\ . An important usage of these flags is to specify non default behavior for when the dynamic library loader binds library references to exported symbols and if the bound references are put into process local or global scope. For 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.

.. function:: dlopen_e(libfile::AbstractString [, flags::Integer])
Expand Down
60 changes: 23 additions & 37 deletions src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,15 @@
extern "C" {
#endif

// The empty extension at the beginning and the end is a trick to change
// the order of the loop.
#if defined(__APPLE__)
static char const *const extensions[] = { "", ".dylib", "" };
static char const *const extensions[] = { "", ".dylib" };
#elif defined(_OS_WINDOWS_)
static char const *const extensions[] = { "", ".dll", "" };
static char const *const extensions[] = { "", ".dll" };
extern int needsSymRefreshModuleList;
#else
static char const *const extensions[] = { "", ".so", "" };
static char const *const extensions[] = { "", ".so" };
#endif
#define N_EXTENSIONS (sizeof(extensions) / sizeof(char*) - 1)
#define N_EXTENSIONS (sizeof(extensions) / sizeof(char*))

static int endswith_extension(const char *path)
{
Expand Down Expand Up @@ -118,11 +116,10 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t
int i;
uv_stat_t stbuf;
void *handle;
// This determines if we try the no-extension name first or last
// We want to make sure the last one we try has higher chance of being
// a real file since the error reported will otherwise be a unhelpful
// file not found error due to the extra or missing extension name.
int hasext = endswith_extension(modname);
int abspath;
// number of extensions to try — if modname already ends with the
// standard extension, then we don't try adding additional extensions
int n_extensions = endswith_extension(modname) ? 1 : N_EXTENSIONS;

/*
this branch returns handle of libjulia
Expand All @@ -139,26 +136,15 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t
#endif
goto done;
}
/*
this branch shortcuts absolute paths
*/
#ifdef _OS_WINDOWS_
else if (modname[1] == ':') {
#else
else if (modname[0] == '/') {
#endif
handle = jl_dlopen(modname, flags);
if (handle)
goto done;
// bail out and show the error if file actually exists
if (jl_stat(modname, (char*)&stbuf) == 0)
goto notfound;
}

abspath = isabspath(modname);

/*
this branch permutes all base paths in DL_LOAD_PATH with all extensions
note: skip when !jl_base_module to avoid UndefVarError(:DL_LOAD_PATH)
note: skip when !jl_base_module to avoid UndefVarError(:DL_LOAD_PATH),
and also skip for absolute paths
*/
else if (jl_base_module != NULL) {
if (!abspath && jl_base_module != NULL) {
jl_array_t *DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH"));
if (DL_LOAD_PATH != NULL) {
size_t j;
Expand All @@ -167,9 +153,8 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t
size_t len = strlen(dl_path);
if (len == 0)
continue;
for (i=0; i < N_EXTENSIONS; i++) {
// Do the no-ext one last if hasext == 1
const char *ext = extensions[i + hasext];
for (i=0; i < n_extensions; i++) {
const char *ext = extensions[i];
path[0] = '\0';
if (dl_path[len-1] == PATHSEPSTRING[0])
snprintf(path, PATHBUF, "%s%s%s", dl_path, modname, ext);
Expand All @@ -187,9 +172,8 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t
}

// now fall back and look in default library paths, for all extensions
for(i=0; i < N_EXTENSIONS; i++) {
// Do the no-ext one last if hasext == 1
const char *ext = extensions[i + hasext];
for(i=0; i < n_extensions; i++) {
const char *ext = extensions[i];
path[0] = '\0';
snprintf(path, PATHBUF, "%s%s", modname, ext);
handle = jl_dlopen(path, flags);
Expand All @@ -199,9 +183,11 @@ static void *jl_load_dynamic_library_(const char *modname, unsigned flags, int t

#if defined(__linux__) || defined(__FreeBSD__)
// check map of versioned libs from "libX" to full soname "libX.so.ver"
handle = jl_dlopen_soname(modname, strlen(modname), flags);
if (handle)
goto done;
if (!abspath && n_extensions > 1) { // soname map only works for libX
handle = jl_dlopen_soname(modname, strlen(modname), flags);
if (handle)
goto done;
}
#endif

notfound:
Expand Down
10 changes: 3 additions & 7 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,9 @@ int isabspath(const char *in)
if (c0 == '/' || c0 == '\\') {
return 1; // absolute path relative to %CD% (current drive), or UNC
}
else {
int s = strlen(in);
if (s > 2) {
char c1 = in[1];
char c2 = in[2];
if (c1 == ':' && (c2 == '/' || c2 == '\\')) return 1; // absolute path
}
else if (c0 && in[1] == ':') {
char c2 = in[2];
return c2 == '/' || c2 == '\\'; // absolute path with drive name
}
#else
if (in[0] == '/') return 1; // absolute path
Expand Down
2 changes: 2 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,8 @@ STATIC_INLINE void *jl_get_frame_addr(void)

JL_DLLEXPORT jl_array_t *jl_array_cconvert_cstring(jl_array_t *a);

int isabspath(const char *in);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit b506041

Please sign in to comment.