Skip to content

Commit 80049a5

Browse files
authored
[dylink] Match behaviour between sync and async versions of dlopen. NFC (#20207)
In particular honoer LD_LIBRARY_PATH, and check for already loaded libraries.
1 parent 6e9e558 commit 80049a5

File tree

2 files changed

+44
-21
lines changed

2 files changed

+44
-21
lines changed

system/lib/libc/dynlink.c

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,29 @@ static int path_find(const char *name, const char *s, char *buf, size_t buf_size
514514
}
515515
}
516516

517+
// Resolve filename using LD_LIBRARY_PATH
518+
static const char* resolve_path(char* buf, const char* file, size_t buflen) {
519+
if (!strchr(file, '/')) {
520+
const char* env_path = getenv("LD_LIBRARY_PATH");
521+
if (env_path && path_find(file, env_path, buf, buflen) == 0) {
522+
dbg("dlopen: found in LD_LIBRARY_PATH: %s", buf);
523+
return buf;
524+
}
525+
}
526+
return file;
527+
}
528+
529+
// Search for library name to see if it's already loaded
530+
static struct dso* find_existing(const char* file) {
531+
for (struct dlevent* e = head; e; e = e->next) {
532+
if (e->sym_index == -1 && !strcmp(e->dso->name, file)) {
533+
dbg("dlopen: already opened: %p", e->dso);
534+
return e->dso;
535+
}
536+
}
537+
return NULL;
538+
}
539+
517540
// Internal version of dlopen with typed return value.
518541
// Without this, the compiler won't tell us if we have the wrong return type.
519542
static struct dso* _dlopen(const char* file, int flags) {
@@ -533,25 +556,12 @@ static struct dso* _dlopen(const char* file, int flags) {
533556
dlsync();
534557
#endif
535558

536-
struct dso* p;
537-
538-
/* Resolve filename using LD_LIBRARY_PATH */
539559
char buf[2*NAME_MAX+2];
540-
if (!strchr(file, '/')) {
541-
const char* env_path = getenv("LD_LIBRARY_PATH");
542-
if (env_path && path_find(file, env_path, buf, sizeof buf) == 0) {
543-
dbg("dlopen: found in LD_LIBRARY_PATH: %s", buf);
544-
file = buf;
545-
}
546-
}
560+
file = resolve_path(buf, file, sizeof buf);
547561

548-
/* Search for the name to see if it's already loaded */
549-
for (struct dlevent* e = head; e; e = e->next) {
550-
if (e->sym_index == -1 && !strcmp(e->dso->name, file)) {
551-
dbg("dlopen: already opened: %p", e->dso);
552-
p = e->dso;
553-
goto end;
554-
}
562+
struct dso* p = find_existing(file);
563+
if (p) {
564+
goto end;
555565
}
556566

557567
p = load_library_start(file, flags);
@@ -580,16 +590,24 @@ void* dlopen(const char* file, int flags) {
580590

581591
void emscripten_dlopen(const char* filename, int flags, void* user_data,
582592
em_dlopen_callback onsuccess, em_arg_callback_func onerror) {
593+
dbg("emscripten_dlopen: %s", filename);
583594
if (!filename) {
584-
onsuccess(user_data, head);
595+
onsuccess(user_data, head->dso);
585596
return;
586597
}
587598
do_write_lock();
588599
#ifdef _REENTRANT
589600
// Make sure we are in sync before performing any write operations.
590601
dlsync();
591602
#endif
592-
struct dso* p = load_library_start(filename, flags);
603+
char buf[2*NAME_MAX+2];
604+
filename = resolve_path(buf, filename, sizeof buf);
605+
struct dso* p = find_existing(filename);
606+
if (p) {
607+
onsuccess(user_data, p);
608+
return;
609+
}
610+
p = load_library_start(filename, flags);
593611
if (!p) {
594612
do_write_unlock();
595613
onerror(user_data);

test/test_other.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6777,10 +6777,15 @@ def test_dlopen_rtld_global(self):
67776777

67786778
def test_dlopen_async(self):
67796779
create_file('side.c', 'int foo = 42;\n')
6780-
self.run_process([EMCC, 'side.c', '-o', 'libside.so', '-sSIDE_MODULE'])
6780+
create_file('pre.js', r'''
6781+
Module.preRun = () => {
6782+
ENV['LD_LIBRARY_PATH']='/usr/lib';
6783+
};
6784+
''')
6785+
self.run_process([EMCC, 'side.c', '-o', 'tmp.so', '-sSIDE_MODULE'])
67816786
self.set_setting('MAIN_MODULE', 2)
67826787
self.set_setting('EXIT_RUNTIME')
6783-
self.do_other_test('test_dlopen_async.c')
6788+
self.do_other_test('test_dlopen_async.c', ['--pre-js=pre.js', '--embed-file', 'tmp.so@/usr/lib/libside.so'])
67846789

67856790
def test_dlopen_promise(self):
67866791
create_file('side.c', 'int foo = 42;\n')

0 commit comments

Comments
 (0)