Quentin
Quentin

Reputation: 71

Segfault on calling function pointer obtained with dlopen() in Rust

I am currently playing with POSIX functions defined in dlfcn.h with Rust, with the goal of calling a function in a separated .so file.

The project actually contains 2 crates:

The dynamic library is 4 lines long and here is the code:

#[no_mangle]
pub extern "Rust" fn hello_world() -> String {
    String::from("Hello World !")
}

But the executable binary is a bit more complex and looks like this:

#![feature(str_from_raw_parts)]

fn open_dl(path: &str) -> Result<*mut libc::c_void, String> {
    let path = format!("{path}\0");

    let path: *const libc::c_char = unsafe { std::mem::transmute(path.as_ptr()) };
    let handle = unsafe { libc::dlopen(path, libc::RTLD_NOW) };

    if handle.is_null() {
        let dl_error: &str = unsafe {
            let ptr = libc::dlerror();
            let len = libc::strlen(ptr);
            std::str::from_raw_parts(std::mem::transmute(ptr), len)
        };

        return Err(String::from(dl_error));
    }
    Ok(handle)
}

fn get_symbol<T>(handle: *mut libc::c_void, symbol: &str) -> Result<&T, String> {
    let symbol_name = format!("{symbol}\0");
    let symbol = unsafe { libc::dlsym(handle, std::mem::transmute(symbol_name.as_ptr())) };

    if symbol.is_null() {
        let dl_error: &str = unsafe {
            let ptr = libc::dlerror();
            let len = libc::strlen(ptr);
            std::str::from_raw_parts(std::mem::transmute(ptr), len)
        };

        return Err(String::from(dl_error));
    }
    return unsafe { Ok(std::mem::transmute(symbol)) };
}

fn main() -> Result<(), String> {
    let handle = open_dl("./libfoo.so")?;

    // Tricky part, get the symbol with the correct signature and calling it
    let symbol: &fn() -> String = get_symbol(handle, "hello_world")?;
    let val = symbol(); // Blows up

    println!("{val}");

    Ok(())
}

My problem is that get_symbol seems to work fine, the obtained pointer is not null, so I would expect that calling the function behind it would cause no issue, but I get a SEGFAULT when I try to. Do you wonder why it does SEGFAULT ?

Upvotes: 0

Views: 133

Answers (1)

rostamn739
rostamn739

Reputation: 421

The return type of get_symbol is wrong.

dlsym returns *mut c_void which (in the case of function pointers) contains Option<extern "C" fn(...)> internally.

You have to cast the return value to Option directly, not to a reference.

Remember that in Rust function pointers do not imply pointer semantics, much less reference semantics.

Upvotes: 1

Related Questions