rust_libloading
rust_libloading copied to clipboard
Document unsafety of functions with 'static-containing return types.
Return values from functions that contain 'static
lifetimes are not reduced to the lifetime of the loaded library, and can outlive it.
Preventing this is probably impossible (especially when the 'static
is hidden inside a type like Wrapper(&'static u32)
), but the docs could warn about it.
Here's one example that segfaults:
Cargo.toml:
[package]
name = "unsafe_libloading"
version = "0.0.0"
[lib]
path = "lib.rs"
name = "loadee"
crate-type = ["dylib"]
[[bin]]
name = "loader"
path = "main.rs"
[dependencies]
libloading = "0.5"
lib.rs:
#[no_mangle]
pub fn get_str() -> &'static str {
"Hello, world"
}
main.rs:
extern crate libloading;
fn main() -> libloading::Result<()> {
let lib = libloading::Library::new("libloadee.so")?;
let return_value: &'static str = {
let fun: libloading::Symbol<extern fn()->&'static str> = unsafe{ lib.get(b"get_str") }?;
fun()
};
drop(lib);
println!("return value: {}", return_value);
Ok(())
}
I assume this issue also applies to loaded global variables, but dereferencing those produced bogus values even without dropping lib
:
lib.rs:
#[no_mangle]
pub static REF: &'static u16 = &19;
main.rs:
extern crate libloading;
fn main() -> libloading::Result<()> {
let lib = libloading::Library::new("libloadee.so")?;
let var: libloading::Symbol<&'static u16> = unsafe{ lib.get(b"REF") }?;
let dereferenced: u16 = **ref;
println!("variable: {} = 0x{:x}", dereferenced, dereferenced);
Ok(())
}
prints "variable: 27312 = 0x6ab0"
Return values from functions that contain 'static lifetimes are not reduced to the lifetime of the loaded library, and can outlive it. Preventing this is probably impossible…
Indeed, I don’t see a way to prevent this, although this is not necessarily invalid (i.e. the value returned by a function is not necessarily 'lib
. It might be worthwhile to mention this problem somewhere in the documentation.
I assume this issue also applies to loaded global variables, but dereferencing those produced bogus values even without dropping lib
Type of your Symbol
is wrong here (lacking one level of indirection… it might be worthwhile to add a wrapper type for this on the libloading side…). But otherwise, yes, the problem is also present in this case.
This could be fixed by a smart wrapper type libloading::LibraryStatic*<u16>
, but that definitely feels… inelegant.
Thanks for the report!
I didn't realize variables must be loaded via a pointer type, although it makes sense with fn types being pointers under the hood.
With LibraryStatic
, do you mean a completely different Library
type for accessing statics, or a Symbol
variant such as StaticSymbol
?
I don't see how StaticSymbol
could prevent getting a reference to the 'static
reference in struct Wrapper(&'static u8)
, but it would fix #13 for variables and stop this from compiling:
extern crate libloading;
fn main() -> libloading::Result<()> {
let v: &u16 = {
let lib = libloading::Library::new("libloadee.so")?;
let sym: libloading::Symbol<&u16> = unsafe{ lib.get(b"VAR") }?;
*sym
};
println!("{}", *v);
Ok(())
}