Reputation: 71
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
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