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

Dropping and reloading a dylib on macOS returns the old version, but only if the dylib uses the stdlib #59

Closed
mistodon opened this issue Oct 23, 2019 · 7 comments

Comments

@mistodon
Copy link

I'm attempting to get some sort of code hotswapping working by dynamically re-loading a crate at runtime when it changes.

I've noticed weirdly that it works if the dylib isn't using stdlib (no print!, no Strings, etc.) - but as soon as you add any reference to something from std in the dylib, it breaks the reloading until the program quits. Or rather, the Library reloads, but returns the outdated version (same handle as before).

I pushed a crate with a repo in it: https://github.com/mistodon/dlopen_issue - it's as concise as I could make a working example. But basically:

To reproduce, on macOS:

  1. Load a dylib
  2. Drop it
  3. Recompile it
  4. Load it again
  5. Observe that:
    a. If the dylib uses std, the new version has not been loaded
    b. If the dylib does not use std, the new version has been loaded

I'm not sure if this is a bug in libloading, or dylib, or if I'm doing something wrong. Or possibly this is intended behaviour and I'm not understanding something? But anyway I'm baffled and not sure where to look next.

Thanks for reading, and sorry it's a bit long-winded!

@nagisa
Copy link
Owner

nagisa commented Oct 23, 2019

This is a macOS peculiarity which happened in order to fix/work-around bugs related to dynamic library handling in macOS, like #5.

Standard library uses thread-local variables extensively. As per this presentation unloading shared libraries that use thread-local variables is a no-op. Therefore loading a new dylib will just fetch you the old one that’s already loaded.

@nagisa
Copy link
Owner

nagisa commented Oct 23, 2019

As per the presentation, please fill a radar against macOS.

For now closing this as there is nothing actionable to be done here on the side of libloading. Feel free to continue the discussion or ask further questions, though.

@nagisa nagisa closed this as completed Oct 23, 2019
@mistodon
Copy link
Author

Ah, that's interesting. It makes a lot more sense now.

I have one question, if you (or anyone else) happen to know. For my specific use case, I don't care too much about leaking resources. Can I load a second version of the same library under a different name and handle? I did try this (copying the lib to a new path and loading that) but I'm still getting the same handle. Any idea how dyld is resolving them to the same handle?

@nagisa
Copy link
Owner

nagisa commented Oct 23, 2019

There might be an optimisation in macOS to not load identical libraries at different paths, but if the libraries are actually different and at different locations, reloading should work fine. There are a couple of examples around the ecosystem of people having successes with that kind of approach.

@mistodon
Copy link
Author

Nice, I must be missing something on my end. I'll do some more experimentation. Also, you've been really helpful and quick to respond, thank you 🙂

@mistodon
Copy link
Author

mistodon commented Oct 24, 2019

Just in case it's useful for anyone else - it wasn't enough to change the file name of the dylib. To avoid dyld caching it regardless, I had to also change the install name with install_name_tool -id '' libfoo.dylib.

I presume any argument to -id would work? But an empty string does for me.

@JoshuaBatty
Copy link

Thanks heaps @mistodon your install_name_tool trick worked a charm.

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

No branches or pull requests

3 participants