-
Notifications
You must be signed in to change notification settings - Fork 13k
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
As of 1.37.0, dylib
shared libraries no longer support interpositioning of functions defined in C
#66265
Comments
Related #65610 |
This can be worked around with a |
I hit this issue too, and the proposed workaround is not working for me, at least. |
I agree that the proposed workaround does not work. I'm still stuck on Rust 1.36 because of this change, but I've prototyped the following workaround to remove the
(If using cargo, you can accomplish this as a one-off by doing Sorry for the delay in noticing you needed this, @itamarst! |
@rustbot modify labels to +I-prioritize |
Assigning |
I encountered a stable-to-stable linking regression while working with a project that compiles to an x86-64 ELF shared library for Linux. The library exports a Rust interface, but also includes some wrappers of libc functions, written in C, that need to shadow the system implementations via interpositioning. I perform the final linking step using rustc, which works correctly under rustc 1.36.0 but subtly fails under 1.37.0: the libc wrapper functions are not exported as dynamic symbols, causing the program to behave differently at runtime. The offending patchset appears to be #59752, and I've managed to construct a minimal example to illustrate the problem...
Minimal example
The library consists of two files:
interpose.rs
defines a single-function Rust API:exit.c
defines an implementation ofexit()
that should shadow the one in libc:The following short program,
hotel_california.rs
, will be used to test its behavior:Expected behavior (past stable releases)
This is how the program used to behave when built with a stable compiler:
Notice that the call to
exit()
gets intercepted and does not, in fact, exit the program.Broken behavior (as of 1.37.0 stable)
Newer versions of the compiler result in different program output:
Discussion: symbol table entries
The problem is evident upon examining the static and dynamic symbol tables of the
libinterpose.so
file. When built with rustc 1.36.0, we see thatexit
is exported in the dynamic symbol table (indicated by theD
):In contrast, the output from rustc 1.37.0 doesn't list
exit
in the dynamic symbol table because the static symbol table lists it as a local symbol (l
) rather than a global one (g
):Discussion: linker invocation
I was curious to see how rustc was invoking cc to link the program, so I traced the command-line arguments by substituting the fake linker
false
. Here's with rustc 1.36.0:And with rustc 1.37.0:
Notice the newly-added
-Wl,--version-script
flag, which has no knowledge of the symbols from theexit.o
object file.Discussion: static library instead of bare object file
One might be tempted to work around the problem by telling rustc about the object file so it can keep the symbols it defines global. I tried this on rustc 1.36.0:
This has a very surprising result: the exit symbol is not present at all in
libinterpose.so
, but it does exist somewhere (the LLVM bitcode for monomorphization, maybe?) that allows the compiler to statically link it into the executable:This is no good either because it leads to subtly different interposition behavior. For example:
exit()
could be further shadowed by libraries loaded via theLD_PRELOAD
environment variable. Building it directly into the executable breaks this.cc
andld
apply very different optimizations toexit()
because it is now part of a PIE instead of a PIC object; depending on how wrapping is implemented, this can break it and even result in infinite recursion.libinterpose.so
, it will no longer get the interposed version ofexit()
. This is a very real situation for my project, because it also exports a C API via Rust's FFI.Possible mitigation: expose a
-Climit_rdylib_exports
command-line switchThe simplest way to allow users to work around this would be to allow invokers of rustc to opt out of the change introduced by #59752. However, the change is likely to have broken other use cases as well, so perhaps it needs to be revisited in more detail.
See also
The same changeset seems to be causing problems with inline functions, as observed at #65610.
The text was updated successfully, but these errors were encountered: