rust_libloading
rust_libloading copied to clipboard
Thread-local RefCell containing heap-allocated object produces unexpected library re-loading behavior
I'm running into an issue with static thread local storage that contains a heap-allocated object when loading a library.
Given a simple library:
#[no_mangle]
pub fn lib_func() {
thread_local! {
static CELL: RefCell<Box<u8>> = RefCell::new(Box::new(1));
}
CELL.with_borrow(|cell| {
println!("Cell: {cell}");
});
}
and a main program that will repeatedly load said library:
loop {
unsafe {
let lib = libloading::Library::new("../target/release/libplugins.so")?;
let lib_func: libloading::Symbol<fn()> = lib.get(b"lib_func")?;
lib_func();
}
thread::sleep(Duration::from_secs(1));
}
The issue I'm seeing: Calling lib_func
from the main loop initially prints Cell: 1
as expected. If you change the value to say, 2
, within the RefCell in lib_func
and recompile, the main loop will still repeatedly print Cell: 1
.
If you replace the RefCell
with a plain Cell
, then once changing the value to 2
and recompiling, it would start printing Cell: 2
, as I would expect.
The Box<u8>
within the RefCell
can be replaced with any other heap-allocated object such as a String
or Vec
to see the same unexpected behavior.
Rust info:
$ cargo -V -v
cargo 1.78.0 (54d8815d0 2024-03-26)
release: 1.78.0
commit-hash: 54d8815d04fa3816edc207bbc4dd36bf18014dbc
commit-date: 2024-03-26
host: x86_64-unknown-linux-gnu
libgit2: 1.7.2 (sys:0.18.2 vendored)
libcurl: 8.6.0-DEV (sys:0.4.72+curl-8.6.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w 11 Sep 2023
os: Ubuntu 22.04 (jammy) [64-bit]
Trimmed down the examples and explanation for clarity. Also included Rust version info.
You are aware that what you are doing here is highly platform dependant. For example musl-libc doesnt even support library unloading. Its a noop there.
Glibc to my knowlege has a refcounter and does actually to some extend unload librarys.
I do not know with which criteria windows decides to remove a dll from the process address space after you call CloseHandle on the libraries handle.
I personally try to never unload shared objects/libraries as most libs do not even implement unloading properly. You are probably observing just this in your example.