Skip to content
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

Implib IMPLIB_EXPORT_SHIMS triggers an assertion when imported DSO has initializers referring to its public symbols. #18

Open
Artem-B opened this issue Aug 2, 2022 · 3 comments

Comments

@Artem-B
Copy link
Contributor

Artem-B commented Aug 2, 2022

lib_handle = dlopen("$load_name", RTLD_LAZY | RTLD_GLOBAL);

When implib is built to export wrapped symbols (-DIMPLIB_EXPORT_SHIMS), the imported library initializers may end up resolving some of the symbols to the already-available symbols provided by the wrapper and that triggers an assertion checking is_lib_loading -- we're still in the middle of calling dlopen() at that point.

One way to deal with that is to dlopen() the wrapped library with RTLD_DEEPBIND. This would tell dynamic linker to bind the symbols to the library itself and avoid the unfortunate recursion. It would bypass the implib's wrapper, but I think it's the right thing to do when we build implib with visible symbols.

We may want to make it a user-controllable option, in case someone may need to guarantee that all references to a symbol go through the wrapper, but that would have to be a trade-off as in that case they would lose the ability to import libraries that refer to themselves in their initializers.

@Artem-B Artem-B changed the title Using implib from a shared library with IMPLIB_EXPORT_SHIMS triggers an assertion. Implib IMPLIB_EXPORT_SHIMS triggers an assertion when imported DSO has initializers referring to its public symbols. Aug 2, 2022
@Artem-B
Copy link
Contributor Author

Artem-B commented Aug 2, 2022

Looks like the issue is more general and may not be limited to implib's use from a shared library. I've updated the title and description

@yugr
Copy link
Owner

yugr commented Aug 3, 2022

Yup, we ran into this during gh-15 and unfortunately I do not have a good solution for it.

One way to deal with that is to dlopen() the wrapped library with RTLD_DEEPBIND. This would tell dynamic linker to bind the symbols to the library itself and avoid the unfortunate recursion. It would bypass the implib's wrapper, but I think it's the right thing to do when we build implib with visible symbols.

Right, this is one solution. It has a disadvantage of changing the symbol resolution logic which may not be suitable for some users so I decided to not enable it by default. For now users may load library with RTLD_DEEPBIND by using --dlopen-callback.

It would be great if glibc provided us with APIs for separate library loading and ctor execution...

For completeness, the other potential solution would be to detect the is_lib_loading case and run dlopen with RTLD_NOLOAD (or locate library by hand, by searching for library via dl_iterate_phdr). The located library could then be used to call dlsym. Unfortunately it's unclear how to naturally extend this solution to --no-dlopen or --dlopen-callback cases.

@yugr
Copy link
Owner

yugr commented Sep 14, 2022

For completeness, the other potential solution would be to detect the is_lib_loading case and run dlopen with RTLD_NOLOAD (or locate library by hand, by searching for library via dl_iterate_phdr). The located library could then be used to call dlsym. Unfortunately it's unclear how to naturally extend this solution to --no-dlopen or --dlopen-callback cases.

Actually it's possible to just call dlopen with default arguments (i.e. without RTLD_NOLOAD) inside the constructor and it will return the loaded library. So we can expect that in most cases just calling the load callback second time when is_lib_loading is true will return the handle.

In --no-dlopen case we could search for library via dl_iterate_phdr and then dlopen it.

This is still fragile though. In particular

  • load callback needs to be reentrant
  • the approach will not work if library is loaded by custom loader

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants