Skip to content

Commit

Permalink
Move LD_LIBRARY_PATH handling to native code. NFC (#19321)
Browse files Browse the repository at this point in the history
Split out from #19310
  • Loading branch information
sbc100 committed May 10, 2023
1 parent f2cca1a commit 9eff02b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 29 deletions.
19 changes: 0 additions & 19 deletions src/library_dylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -1071,25 +1071,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 : {};

Expand Down
42 changes: 42 additions & 0 deletions system/lib/libc/dynlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include <emscripten/console.h>
#include <emscripten/threading.h>
Expand Down Expand Up @@ -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) {
Expand All @@ -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)) {
Expand Down
29 changes: 19 additions & 10 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -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);

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

0 comments on commit 9eff02b

Please sign in to comment.