Skip to content

Commit d5c3091

Browse files
authored
[dylink] Fix multiple loading of the same library with RTLD_LOCAL (#20210)
When a library is loaded for a second time we were only handling the RTLD_GLOBAL case. Fixes: #20203
1 parent dfc000d commit d5c3091

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

src/library_dylink.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -959,15 +959,18 @@ var LibraryDylink = {
959959
var dso = LDSO.loadedLibsByName[libName];
960960
if (dso) {
961961
// the library is being loaded or has been loaded already.
962-
//
963-
// however it could be previously loaded only locally and if we get
964-
// load request with global=true we have to make it globally visible now.
965-
if (flags.global && !dso.global) {
966-
dso.global = true;
967-
if (dso.exports !== 'loading') {
968-
// ^^^ if module is 'loading' - symbols merging will be eventually done by the loader.
969-
mergeLibSymbols(dso.exports, libName)
962+
#if ASSERTIONS
963+
assert(dso.exports !== 'loading', `Attempt to load '${libName}' twice before the first load completed`);
964+
#endif
965+
if (!flags.global) {
966+
if (localScope) {
967+
Object.assign(localScope, dso.exports);
970968
}
969+
} else if (!dso.global) {
970+
// The library was previously loaded only locally but not
971+
// we have a request with global=true.
972+
dso.global = true;
973+
mergeLibSymbols(dso.exports, libName)
971974
}
972975
// same for "nodelete"
973976
if (flags.nodelete && dso.refcount !== Infinity) {

test/test_core.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4102,29 +4102,46 @@ def test_dlfcn_asyncify(self):
41024102

41034103
@needs_dylink
41044104
def test_dlfcn_rtld_local(self):
4105+
# Create two shared libraries that both depend on a third.
4106+
# liba.so -> libsub.so
4107+
# libb.so -> libsub.so
41054108
create_file('liba.c', r'''
41064109
#include <stdio.h>
41074110
4108-
void func_b();
4111+
void func_sub();
41094112
41104113
void func_a() {
41114114
printf("func_a\n");
41124115
// Call a function from a dependent DSO. This symbol should
41134116
// be available here even though liba itself is loaded with RTLD_LOCAL.
4114-
func_b();
4117+
func_sub();
41154118
}
41164119
''')
41174120

41184121
create_file('libb.c', r'''
41194122
#include <stdio.h>
41204123
4124+
void func_sub();
4125+
41214126
void func_b() {
41224127
printf("func_b\n");
4128+
// Call a function from a dependent DSO. This symbol should
4129+
// be available here even though liba itself is loaded with RTLD_LOCAL.
4130+
func_sub();
4131+
}
4132+
''')
4133+
4134+
create_file('libsub.c', r'''
4135+
#include <stdio.h>
4136+
4137+
void func_sub() {
4138+
printf("func_sub\n");
41234139
}
41244140
''')
41254141

4126-
self.build_dlfcn_lib('libb.c', outfile='libb.so')
4127-
self.build_dlfcn_lib('liba.c', outfile='liba.so', emcc_args=['libb.so'])
4142+
self.build_dlfcn_lib('libsub.c', outfile='libsub.so')
4143+
self.build_dlfcn_lib('libb.c', outfile='libb.so', emcc_args=['libsub.so'])
4144+
self.build_dlfcn_lib('liba.c', outfile='liba.so', emcc_args=['libsub.so'])
41284145

41294146
self.prep_dlfcn_main(['liba.so', 'libb.so', '-L.'])
41304147
create_file('main.c', r'''
@@ -4133,28 +4150,41 @@ def test_dlfcn_rtld_local(self):
41334150
#include <stdio.h>
41344151
41354152
int main() {
4153+
void* handle;
4154+
void (*f)();
4155+
41364156
printf("main\n");
4137-
void* handle = dlopen("liba.so", RTLD_NOW|RTLD_LOCAL);
4157+
// Call a function from libb
4158+
handle = dlopen("liba.so", RTLD_NOW|RTLD_LOCAL);
41384159
assert(handle);
41394160
4140-
void (*f)();
41414161
f = dlsym(handle, "func_a");
41424162
assert(f);
41434163
f();
41444164
4145-
// Verify that symbols from liba.so and libb.so are not globally
4165+
// Same for libb
4166+
handle = dlopen("libb.so", RTLD_NOW|RTLD_LOCAL);
4167+
assert(handle);
4168+
4169+
f = dlsym(handle, "func_b");
4170+
assert(f);
4171+
f();
4172+
4173+
// Verify that symbols from all three libraries are not globally
41464174
// visible.
4147-
void* func_a = dlsym(RTLD_DEFAULT, "func_a");
4148-
assert(func_a == NULL);
4149-
void* func_b = dlsym(RTLD_DEFAULT, "func_b");
4150-
assert(func_b == NULL);
4175+
f = dlsym(RTLD_DEFAULT, "func_a");
4176+
assert(f == NULL);
4177+
f = dlsym(RTLD_DEFAULT, "func_b");
4178+
assert(f == NULL);
4179+
f = dlsym(RTLD_DEFAULT, "func_sub");
4180+
assert(f == NULL);
41514181
41524182
printf("done\n");
41534183
return 0;
41544184
}
41554185
''')
41564186

4157-
self.do_runf('main.c', 'main\nfunc_a\nfunc_b\ndone\n')
4187+
self.do_runf('main.c', 'main\nfunc_a\nfunc_sub\nfunc_b\nfunc_sub\ndone\n')
41584188

41594189
def dylink_test(self, main, side, expected=None, header=None, force_c=False,
41604190
main_module=2, **kwargs):

test/test_other.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8339,8 +8339,7 @@ def test_side_module_naming(self):
83398339
self.assertTrue(building.is_wasm_dylib(target))
83408340

83418341
create_file('main.c', '')
8342-
self.run_process([EMCC, '-sMAIN_MODULE=2', 'main.c', '-Werror', target])
8343-
self.run_js('a.out.js')
8342+
self.do_runf('main.c', emcc_args=['-sMAIN_MODULE=2', 'main.c', '-Werror', target])
83448343

83458344
def test_side_module_missing(self):
83468345
self.run_process([EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'libside1.wasm'])

0 commit comments

Comments
 (0)