rust_libloading: TLS destructors are not run on Library::drop resulting in illegal instruction on OS X

Hi, thanks for making this library, it’s really useful to me.

Unfortunately, when trying out a really simple use case, I get an Illegal Hardware Instruction error. The Rust code I’m using to load the dylib is:

extern crate libloading;

use libloading::{Library, Symbol};

fn main() {
    let lib = Library::new("../test/target/release/libtest.dylib").unwrap();
    let sym: Symbol<extern fn() -> ()> = unsafe {lib.get(b"testing")}.unwrap();
    sym();
}

The dylib I’m loading contains a single function:

#[no_mangle]
pub fn testing() {
    println!("YES!");
}

The dylib’s Cargo.toml file contains the needed crate-type = ["dylib"] qualifier.

I wrote some equivalent C code (loading the exact same Rust library from above), which works perfectly fine (no errors):

#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char *argv[]) {
    void *lib = dlopen("../test/target/release/libtest.dylib", RTLD_LAZY);
    void (*sym)(void) = dlsym(lib, "testing");
    sym();
}

Any ideas why this might be happening? The illegal hardware instruction occurs after the main Rust function exits (I can place a print at the end of the main function and it’ll be run, then the error will occur). I’m on OSX 10.11.2, using the most recent stable rust (rustc 1.5.0 (3d7cd77e4 2015-12-04) ).

I narrowed it down to the Drop function on the Library struct. If I comment its contents out, then the error doesn’t happen. I also replaced the Drop function with just a single call to dlclose like so:

    fn drop(&mut self) {
        println!("{}", unsafe { dlclose(self.handle) });
    }

Which prints 0 (meaning the close function didn’t return an error), which is weird.

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Comments: 21 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Since 0.3 you can specify arbitrary flags when opening a library. The RTLD_NODELETE (thanks for reminder @Np2x) essentially acts as implicit mem::forget so you can now do something along the lines of:

let os_lib = libloading::os::unix::Library::open("fname", RTLD_NODELETE | RTLD_NOW)?;
let lib = libloading::Library::from(os_lib);
/* do your stuff */

This should still work while liberating you from having to mem::forget your libraries 😃