-
Notifications
You must be signed in to change notification settings - Fork 105
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
SEGFAULT sometimes occurs when testing libloading code #41
Comments
Amusing. Could you try getting a backtrace with a debugger?
…On Tue, Mar 27, 2018, 08:04 Byeonggon Lee ***@***.***> wrote:
Operating system is Fedora 27.
uname -r
4.15.4-300.fc27.x86_64
When running cargo test multiple times, sometimes test fails raising a
segmentation fault.
#[test]fn libloading() {
let lib = libloading::Library::new("libdltest.so").unwrap();
unsafe {
let test_fn: libloading::Symbol<unsafe extern fn(i32) -> i32> = lib.get(b"test").unwrap();
assert!(test_fn(100) == 200);
}
}
test test::libloading ... error: process didn't exit successfully: `/home/User/test_libloading/target/debug/deps/test_libloading-b3311c80df7834fd libloading` (signal: 11, SIGSEGV: invalid memory reference)
But when this code runs in an executable crate, It seems to run without
the segfault.
fn main() {
let lib = libloading::Library::new("libdltest.so").unwrap();
unsafe {
let test_fn: libloading::Symbol<unsafe extern fn(i32) -> i32> = lib.get(b"test").unwrap();
assert!(test_fn(100) == 200);
}
}
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#41>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AApc0rbIn5hqrwa-lMgTtZH-gBaXcQGvks5tidZYgaJpZM4S8VS->
.
|
I tried debugging using gdb but gdb was unable to get symbols from the test executable for unknown reason.
|
Okay, so it seems to be the same (or a very similar) problem as #5, except this time in Linux. It seems to me that in your case you have a scenario where the Not sure why this does not happen with executables, but it would be nice if you tried the workaround referenced in this comment. |
The workaround you mentioned worked and segfault doesn't seem to occur anymore. But I don't think test_fn uses thread local storage, because the function is very simple. |
I'm seeing the same issue in both tests and executables when loading/unloading modules in threads on linux (~16.04.1-Ubuntu SMP Thu Jul 19 09:46:30 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux) and does not reproduce on recent OS-X). rust-lang/rust#28794 captures the issue well but I think on linux the problems still exists. The workarounds mentioned so far won't work when the module must be loaded/unloaded many times from a thread. One alternative workaround is to load the module, spawn the thread, then unload the module after the thread has been cleaned up. This workaround is also not always viable and really it should be fixed on linux. Anyone familiar with movement on this issue from the linux side? |
Can either of you produce a minimal reproducer? |
Try this out: https://github.com/jackcmay/dynamic_module_segfault |
@jackcmay This is literally the TLS issue, similar one to the issue which OS X fixed by explicitly not unloading the dynamic libraries if they have any thread locals, implicitly applying I’m fairly confident that you can construct a similarly problematic sample when the loader is C/C++ code (i.e. taking Just like the OS X counterpart #5, I’m inclined to call this issue not-a-bug in In your case a viable workaround, if |
Ok, the workaround with // Load and initialize library
#[cfg(target_os = "linux")]
let library: Library = {
// Load library with `RTLD_NOW | RTLD_NODELETE` to fix a SIGSEGV
::libloading::os::unix::Library::open(Some(path.as_ref()), 0x2 | 0x1000)?.into()
};
#[cfg(not(target_os = "linux"))]
let library = Library::new(path.as_ref())?; |
The glibc documentation mentions this kind of issue, and how the implementation (supposedly) avoids it: https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables I suspect that this may be a problem with the particular shared library being unloaded. In particular, the glibc implementation seems to rely on the function |
I've created a standalone C reproducer, using It does the following:
This causes the following segfault:
It appears that calling |
There's already a glibc bug report for this: https://sourceware.org/bugzilla/show_bug.cgi?id=21032 Unfortunately, it's been open since 2017 without any feedback. |
While this not a bug in In light of this, I think it might be a good idea of libloading to change its default behavior to not unload shared libraries on Linux when a Concretely, I think that @nagisa What are your thoughts? |
I… don't know. Not unloading the libraries will break a fairly common use-case of hot reloading, as With a recent update of |
I may be wrong, but I would think that hot reloading would be less common than other uses cases (e.g. opening a typical shared library and calling a function). If that's true, then I think it would make more sense for the (less-typical) hot-reloading code to opt into automatically unloading, instead of (more-typical) code needing to opt out of automatically unloading. Looking at the issues that are linked here, it looks like severe; different projects have run into this. I think the fact that the issue occurs in the |
I know that macOS does employ this technique – they don't unload the machine code for libraries that contain thread-local variables, but they are both in a position to selectively apply this, and they are able to make sure this approach of theirs does not end up having unfortunate side effects (unsuccessfully). We're not in that kind of position I fear. If we end up doing this, I would be inclined to adjust the library so that we don't implicitly implement … says @nagisa while looking at "Safer bindings around system dynamic library loading primitives" and wondering if they should remove the first word out of that sentence... |
1236: Update gfx to 0a201d1c406b5119ec11068293a40e50ec0be4c8 r=kvark a=Aaron1011 **Connections** wgpu issue: #246 GFX PR: gfx-rs/gfx#3653 Underlying libloading issue: nagisa/rust_libloading#41 **Description** Pulls in gfx-rs/gfx#3653, which fixes a segfault when using wgpu from a non-main thread. **Testing** The example in #246 should run successfully. I'm not certain how to add an integration test to the repository. Co-authored-by: Aaron Hill <[email protected]>
Operating system is Fedora 27.
When running
cargo test
multiple times, sometimes test fails raising a segmentation fault.But when this code runs in an executable crate, It seems to run without the segfault even when I execute it multiple times.
The text was updated successfully, but these errors were encountered: