diff --git a/src/library_dylink.js b/src/library_dylink.js index f3ae85930657f..5dc387890c874 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1076,25 +1076,6 @@ var LibraryDylink = { filename = PATH.normalize(filename); var searchpaths = []; - var isValidFile = (filename) => { - var target = FS.findObject(filename); - return target && !target.isFolder && !target.isDevice; - }; - - if (!isValidFile(filename)) { - if (ENV['LD_LIBRARY_PATH']) { - searchpaths = ENV['LD_LIBRARY_PATH'].split(':'); - } - - for (var ident in searchpaths) { - var searchfile = PATH.join2(searchpaths[ident], filename); - if (isValidFile(searchfile)) { - filename = searchfile; - break; - } - } - } - var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}}); var localScope = global ? null : {}; diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index a5c19d977b738..94b81d50f3469 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -441,6 +442,37 @@ static void dlopen_onerror(struct dso* dso, void* user_data) { free(data); } +// Modified version of path_open from musl/ldso/dynlink.c +static int path_find(const char *name, const char *s, char *buf, size_t buf_size) { + size_t l; + int fd; + for (;;) { + s += strspn(s, ":\n"); + l = strcspn(s, ":\n"); + if (l-1 >= INT_MAX) return -1; + if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) { + dbg("dlopen: path_find: %s", buf); + struct stat statbuf; + if (stat(buf, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { + return 0; + } + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + case ENAMETOOLONG: + break; + default: + dbg("dlopen: path_find failed: %s", strerror(errno)); + /* Any negative value but -1 will inhibit + * futher path search. */ + return -2; + } + } + s += l; + } +} + // Internal version of dlopen with typed return value. // Without this, the compiler won't tell us if we have the wrong return type. static struct dso* _dlopen(const char* file, int flags) { @@ -462,6 +494,16 @@ static struct dso* _dlopen(const char* file, int flags) { struct dso* p; + /* Resolve filename using LD_LIBRARY_PATH */ + char buf[2*NAME_MAX+2]; + if (!strchr(file, '/')) { + const char* env_path = getenv("LD_LIBRARY_PATH"); + if (env_path && path_find(file, env_path, buf, sizeof buf) == 0) { + dbg("dlopen: found in LD_LIBRARY_PATH: %s", buf); + file = buf; + } + } + /* Search for the name to see if it's already loaded */ for (struct dlevent* e = head; e; e = e->next) { if (e->sym_index == -1 && !strcmp(e->dso->name, file)) { diff --git a/test/test_other.py b/test/test_other.py index 88a25c67274ca..650b26e06221c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6407,10 +6407,11 @@ def test_ld_library_path(self): ''') create_file('pre.js', r''' Module['preRun'] = function () { - ENV['LD_LIBRARY_PATH']='/lib:/usr/lib'; + ENV['LD_LIBRARY_PATH']='/lib:/usr/lib:/usr/local/lib'; }; ''') create_file('main.c', r''' +#include #include #include #include @@ -6422,22 +6423,30 @@ def test_ld_library_path(self): double (*f2)(double); h = dlopen("libhello1.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello1"); + assert(f); f(); dlclose(h); h = dlopen("libhello2.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello2"); + assert(f); f(); dlclose(h); h = dlopen("libhello3.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello3"); + assert(f); f(); dlclose(h); h = dlopen("/usr/local/lib/libhello4.wasm", RTLD_NOW); + assert(h); f2 = dlsym(h, "hello4"); + assert(f2); double result = f2(5.5); dlclose(h); @@ -6447,16 +6456,16 @@ def test_ld_library_path(self): return 0; } ''') - self.run_process([EMCC, '-o', 'libhello1.wasm', 'hello1.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello2.wasm', 'hello2.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello3.wasm', 'hello3.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello4.wasm', 'hello4.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello1.wasm', 'hello1.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello2.wasm', 'hello2.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello3.wasm', 'hello3.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello4.wasm', 'hello4.c', '-sSIDE_MODULE']) self.run_process([EMCC, '--profiling-funcs', '-o', 'main.js', 'main.c', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', - '--embed-file', 'libhello1.wasm@/lib/libhello1.wasm', - '--embed-file', 'libhello2.wasm@/usr/lib/libhello2.wasm', - '--embed-file', 'libhello3.wasm@/libhello3.wasm', - '--embed-file', 'libhello4.wasm@/usr/local/lib/libhello4.wasm', - 'libhello1.wasm', 'libhello2.wasm', 'libhello3.wasm', 'libhello4.wasm', '-sNO_AUTOLOAD_DYLIBS', + '--embed-file', 'hello1.wasm@/lib/libhello1.wasm', + '--embed-file', 'hello2.wasm@/usr/lib/libhello2.wasm', + '--embed-file', 'hello3.wasm@/libhello3.wasm', + '--embed-file', 'hello4.wasm@/usr/local/lib/libhello4.wasm', + 'hello1.wasm', 'hello2.wasm', 'hello3.wasm', 'hello4.wasm', '-sNO_AUTOLOAD_DYLIBS', '--pre-js', 'pre.js']) out = self.run_js('main.js') self.assertContained('Hello1', out)