Skip to content

[dylink] Fix rpath calculation in nested dependencies #24234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

ryanking13
Copy link
Contributor

@ryanking13 ryanking13 commented May 1, 2025

This fixes a bug in rpath calculation in nested dependencies.

Basically, it fixes a case when a relative path is passed to the loadDynamicLibrary.

Think of the following scenario:

  1. libhello.wasm depends on libhello_dep.so depends on libhello_nested_dep.so
  2. [main.c] calls dlopen('/usr/lib/libhello.wasm')
  3. [dynlink.c] calls loadDynamicLibrary('/usr/lib/libhello.wasm') (_dlopen_js ==> dlopenInternal ==> loadDynamicLibrary)
  4. [libdylink.js] inside loadDynamicLibrary('/usr/lib/libhello.wasm'), it loads the dependency libhello_dep.so. When locating libhello_dep.so, it uses parentLibPath: /usr/lib/libhello.wasm it locates the library correctly from /usr/lib/libhello_dep.so.
  5. [libdylink.js] Now we call loadDynamicLibrary('libhello_dep.so'), and it loads its dependency 'libhello_nested_dep.so' first. In this case it uses parentLibPath: libhello_dep.so so it fails to locate the library.

ryanking13 added 4 commits May 1, 2025 10:37
This is an automatic change generated by tools/maint/rebaseline_tests.py.

The following (2) test expectation files were updated by
running the tests with `--rebaseline`:

```
other/codesize/test_codesize_hello_dylink.gzsize: 11735 => 11758 [+23 bytes / +0.20%]
other/codesize/test_codesize_hello_dylink.jssize: 27774 => 27799 [+25 bytes / +0.09%]

Average change: +0.14% (+0.09% - +0.20%)
```
@sbc100 sbc100 changed the title Fix rpath calculation in nested dependencies [dylink] Fix rpath calculation in nested dependencies May 1, 2025
@@ -937,6 +939,7 @@ var LibraryDylink = {
var dso = {
refcount: Infinity,
name,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does that mean that name is always just the basename / so_name? Is is name sometimes absolute too here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, only the dependencies of the libraries will have only the so_name in name. The parent library called from dlopen would have absolute path in the name.

Copy link
Contributor Author

@ryanking13 ryanking13 May 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, only the dependencies of the libraries will have only the so_name in name.

So, I think the alternative approach would be ensuring loadDynamicLibrary always take absolute path. Let me try that approach instead.

flags = {...flags, rpath: { parentLibPath: libName, paths: metadata.runtimePaths }}
var dso = LDSO.loadedLibsByName[libName];
var libPath = dso?.path ?? libName;
flags = {...flags, rpath: { parentLibPath: libPath, paths: metadata.runtimePaths }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should parentLibPath be just the dirname part of the parent? i.e. is there any point in passing a value if its just a basename?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is possible to calculate the dirname here.

For now, the dirname is calculated inside replaceORIGIN function, and the reason I did that was to isolate the code that depends on FS or PATH as much as possible.

If we calculate the dirname here, I think it can be something like:

    var dso = LDSO.loadedLibsByName[libName];
#if FILESYSTEM
    var libPath = PATH.dirname(dso?.path ?? libName);
#endif
    flags = {...flags, rpath: { parentLibPath: libPath, paths: metadata.runtimePaths }}

ryanking13 added 5 commits May 2, 2025 07:28
This is an automatic change generated by tools/maint/rebaseline_tests.py.

The following (2) test expectation files were updated by
running the tests with `--rebaseline`:

```
other/codesize/test_codesize_hello_dylink.gzsize: 11758 => 11757 [-1 bytes / -0.01%]
other/codesize/test_codesize_hello_dylink.jssize: 27799 => 27823 [+24 bytes / +0.09%]

Average change: +0.04% (-0.01% - +0.09%)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants