Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread-local RefCell containing heap-allocated object produces unexpected library re-loading behavior #148

Open
collinoc opened this issue Apr 26, 2024 · 2 comments

Comments

@collinoc
Copy link

collinoc commented Apr 26, 2024

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.

Full Example

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]
@collinoc collinoc changed the title TLS with RefCell with heap-allocated object produces unexpected plugin loading behavior TLS with RefCell with heap-allocated object produces unexpected plugin re-loading behavior Apr 26, 2024
@collinoc collinoc changed the title TLS with RefCell with heap-allocated object produces unexpected plugin re-loading behavior TLS with RefCell with heap-allocated object produces unexpected DSL re-loading behavior Apr 26, 2024
@collinoc collinoc changed the title TLS with RefCell with heap-allocated object produces unexpected DSL re-loading behavior Thread-local RefCell containing heap-allocated object produces unexpected library re-loading behavior May 22, 2024
@collinoc
Copy link
Author

Trimmed down the examples and explanation for clarity. Also included Rust version info.

@AlexanderSchuetz97
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants