diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index 5cb86ee25dd64..230a17111e2a2 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -1103,6 +1103,8 @@ var LibraryDylink = { * @param {Object=} localScope */`, $loadDynamicLibrary: function(libName, flags = {global: true, nodelete: true}, localScope, handle) { + // Avoid duplicate LDSO entries from non-canonical paths (e.g. "sub/../lib.so") + libName = PATH.normalize(libName); #if DYLINK_DEBUG dbg(`loadDynamicLibrary: ${libName} handle: ${handle}`); dbg('existing:', Object.keys(LDSO.loadedLibsByName)); @@ -1280,7 +1282,6 @@ var LibraryDylink = { #if DYLINK_DEBUG dbg('dlopenInternal:', filename); #endif - filename = PATH.normalize(filename); var searchpaths = []; var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}}); diff --git a/test/codesize/test_codesize_cxx_ctors1.json b/test/codesize/test_codesize_cxx_ctors1.json index c41946e53f075..e448beaef3b75 100644 --- a/test/codesize/test_codesize_cxx_ctors1.json +++ b/test/codesize/test_codesize_cxx_ctors1.json @@ -1,10 +1,10 @@ { "a.out.js": 19555, "a.out.js.gz": 8102, - "a.out.nodebug.wasm": 132813, - "a.out.nodebug.wasm.gz": 49862, - "total": 152368, - "total_gz": 57964, + "a.out.nodebug.wasm": 132865, + "a.out.nodebug.wasm.gz": 49889, + "total": 152420, + "total_gz": 57991, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_ctors2.json b/test/codesize/test_codesize_cxx_ctors2.json index 18efe0a1dae85..1ae310d7bf07d 100644 --- a/test/codesize/test_codesize_cxx_ctors2.json +++ b/test/codesize/test_codesize_cxx_ctors2.json @@ -1,10 +1,10 @@ { "a.out.js": 19532, "a.out.js.gz": 8087, - "a.out.nodebug.wasm": 132233, - "a.out.nodebug.wasm.gz": 49515, - "total": 151765, - "total_gz": 57602, + "a.out.nodebug.wasm": 132285, + "a.out.nodebug.wasm.gz": 49542, + "total": 151817, + "total_gz": 57629, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_lto.json b/test/codesize/test_codesize_cxx_lto.json index 68625e72f5a15..76bba51afeab1 100644 --- a/test/codesize/test_codesize_cxx_lto.json +++ b/test/codesize/test_codesize_cxx_lto.json @@ -1,10 +1,10 @@ { "a.out.js": 18902, "a.out.js.gz": 7782, - "a.out.nodebug.wasm": 102066, - "a.out.nodebug.wasm.gz": 39421, - "total": 120968, - "total_gz": 47203, + "a.out.nodebug.wasm": 102126, + "a.out.nodebug.wasm.gz": 39426, + "total": 121028, + "total_gz": 47208, "sent": [ "a (emscripten_resize_heap)", "b (_setitimer_js)", diff --git a/test/codesize/test_codesize_cxx_noexcept.json b/test/codesize/test_codesize_cxx_noexcept.json index 3a3adc6e6e5c9..a4019f2e47fd5 100644 --- a/test/codesize/test_codesize_cxx_noexcept.json +++ b/test/codesize/test_codesize_cxx_noexcept.json @@ -1,10 +1,10 @@ { "a.out.js": 19555, "a.out.js.gz": 8102, - "a.out.nodebug.wasm": 134820, - "a.out.nodebug.wasm.gz": 50699, - "total": 154375, - "total_gz": 58801, + "a.out.nodebug.wasm": 134872, + "a.out.nodebug.wasm.gz": 50724, + "total": 154427, + "total_gz": 58826, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_wasmfs.json b/test/codesize/test_codesize_cxx_wasmfs.json index 6ab72f046d4bd..f4faf7bc4bcb3 100644 --- a/test/codesize/test_codesize_cxx_wasmfs.json +++ b/test/codesize/test_codesize_cxx_wasmfs.json @@ -1,10 +1,10 @@ { "a.out.js": 7053, "a.out.js.gz": 3325, - "a.out.nodebug.wasm": 172891, - "a.out.nodebug.wasm.gz": 63277, - "total": 179944, - "total_gz": 66602, + "a.out.nodebug.wasm": 172943, + "a.out.nodebug.wasm.gz": 63297, + "total": 179996, + "total_gz": 66622, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index cbd43f6d97db7..9dbea1c58fbd8 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -1,10 +1,10 @@ { - "a.out.js": 26596, - "a.out.js.gz": 11356, + "a.out.js": 26604, + "a.out.js.gz": 11359, "a.out.nodebug.wasm": 17730, "a.out.nodebug.wasm.gz": 8957, - "total": 44326, - "total_gz": 20313, + "total": 44334, + "total_gz": 20316, "sent": [ "__syscall_stat64", "emscripten_resize_heap", diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index 492d4a36d3de5..f8a597c2b6728 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,7 +1,7 @@ { - "a.out.js": 244691, + "a.out.js": 244687, "a.out.nodebug.wasm": 577692, - "total": 822383, + "total": 822379, "sent": [ "IMG_Init", "IMG_Load", diff --git a/test/codesize/test_minimal_runtime_code_size_hello_embind.json b/test/codesize/test_minimal_runtime_code_size_hello_embind.json index e47b52ea73673..054a709a8231f 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_embind.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_embind.json @@ -3,8 +3,8 @@ "a.html.gz": 371, "a.js": 7262, "a.js.gz": 3323, - "a.wasm": 7081, - "a.wasm.gz": 3250, - "total": 14891, - "total_gz": 6944 + "a.wasm": 7098, + "a.wasm.gz": 3255, + "total": 14908, + "total_gz": 6949 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_embind_val.json b/test/codesize/test_minimal_runtime_code_size_hello_embind_val.json index 01adce09a02a4..074910e28e3e6 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_embind_val.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_embind_val.json @@ -3,8 +3,8 @@ "a.html.gz": 371, "a.js": 5353, "a.js.gz": 2522, - "a.wasm": 5786, - "a.wasm.gz": 2726, - "total": 11687, - "total_gz": 5619 + "a.wasm": 5802, + "a.wasm.gz": 2732, + "total": 11703, + "total_gz": 5625 } diff --git a/test/test_other.py b/test/test_other.py index 037eca335cf0f..df5ac628ef32a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6884,6 +6884,58 @@ def _build(rpath_flag, expected, **kwds): # case 2) with rpath: success _build(['-Wl,-rpath,$ORIGIN/subdir,-rpath,$ORIGIN'], "Hello\nHello_dep\nHello_nested_dep\nOk\n") + @also_with_wasmfs + def test_dlopen_rpath_no_duplicate_load(self): + # Test that a library loaded both directly and as a transitive dependency + # via $ORIGIN/.. rpath is not loaded twice. Without path normalization in + # loadDynamicLibrary, the LDSO would contain both "/usr/lib/libbase.so" + # and "/usr/lib/subdir/../libbase.so" as separate entries. + create_file('libbase.c', r''' + static int init_count = 0; + __attribute__((constructor)) + void init() { init_count++; } + int base_func() { return 42; } + int get_init_count() { return init_count; } + ''') + create_file('libplugin.c', r''' + extern int base_func(); + int plugin_func() { return base_func() + 1; } + ''') + create_file('main.c', r''' + #include + #include + #include + + int main() { + void *hbase = dlopen("/usr/lib/libbase.so", RTLD_NOW | RTLD_GLOBAL); + assert(hbase); + + void *hplugin = dlopen("/usr/lib/subdir/libplugin.so", RTLD_NOW); + assert(hplugin); + + int (*base_func)() = dlsym(hbase, "base_func"); + int (*plugin_func)() = dlsym(hplugin, "plugin_func"); + int (*get_init_count)() = dlsym(hbase, "get_init_count"); + + assert(base_func() == 42); + assert(plugin_func() == 43); + assert(get_init_count() == 1); + + dlclose(hplugin); + dlclose(hbase); + printf("success\n"); + return 0; + } + ''') + os.mkdir('subdir') + self.run_process([EMCC, '-o', 'libbase.so', 'libbase.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'subdir/libplugin.so', 'libplugin.c', '-sSIDE_MODULE', './libbase.so', '-Wl,-rpath,$ORIGIN/..']) + self.do_runf('main.c', 'success\n', + cflags=['--profiling-funcs', '-sMAIN_MODULE=2', + '--embed-file', 'libbase.so@/usr/lib/libbase.so', + '--embed-file', 'subdir/libplugin.so@/usr/lib/subdir/libplugin.so', + '-L.', '-lbase', '-L./subdir', '-lplugin', '-sNO_AUTOLOAD_DYLIBS']) + def test_dlopen_bad_flags(self): create_file('main.c', r''' #include