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

FAQ: add dlclose() essay from IRC #62

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ note that if you're building a whole system with musl you never need any of
them. you don't need them for building musl, and you don't need them for
building apps against musl (but they won't hurt, generally, either).

# Q: why is dlcose() a NO-OP ?

C does not have any model for functions or pseudo-static data whose lifetimes are not the lifetime of the whole process.
Any attempt to add them is pretty much ad hoc and underspecified because doing it right would require a detailed model compatible with the rest of the language.
It's possible to write individual libraries that are meant to be used with such a model, but it requires explicit care to do it right:
Documenting that you can't keep pointers to their functions or data after unload, etc.
But the problem is that dlopen is recursive, and loading such a module usually involves loading of libraries it depends on.
Libraries which were written to standard C, not this underspecified "C with unloading modules".
They might have registered atexit handlers or otherwise stored pointers to their code or data in places it persists beyond the caller's knowledge of it.
Glibc 'takes care of' the atexit (and dtor) case by doing something wild: executing global ctors at a time other than process termination: at unload time.
This has all sorts of weirdness and violates principle that all dtors are executed in reverse order of ctors<dalias> and if the library was written assuming dtors run at process exit time, it may be doing something that's not appropriate to happen while the process is continuing to run.
Now, you could try to say "ok let's just unload modules meant to be loaded as modules, but refuse to unload recursive deps and anything with dtors"
Well, bad news: gcc/binutils make *all libraries* appear to have dtors as far as the dynamic linker can tell; the dtors might just be a no-op -
and to know that you'd have to interpret code.
The ELF headers actually have a way to signal "never unload this library".
The problem is that the default is backwards; only libraries explicitly created with that flag set have it, whereas, semantically, the default is "unsafe to unload"
Further, managing thread-local-storage lifetime is a lot more problematic when slots can be freed and reused. (actually a lot of ppl think this is why musl doesn't unload libraries, which isn't the case. it's possible to do right, just more work).
On glibc this actually makes for some weird race conditions where a library that 'could be' unloaded doesn't get unloaded, and unloading it either never happens or gets deferred to the next dlclose operation - which breaks anything assuming that dlclose will actually unload.
So programs making this assumption are already broken on glibc too, just with random rare failures rather than failure every time.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Generally I think it would be nice to keep the formatting/wrapping like the other answers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the others are formatted to 80 chars line length, tho md rendering disregards newlines anyway - and as this faq is not meant to be read in a terminal i opted for the quick way...

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you use vim, just select the whole block and gq it. It will auto format the whole thing.

# Q: Why am I getting "error: redefinition of struct ethhdr/tcphdr/etc"?

The application you're trying to compile mixes userspace and kernel headers
Expand Down