Rust: Enforcing lifetimes within (and outside of) dynamically loaded libraries

Viewed 48

I'm exploring dynamically loading libraries with Rust, and would like to get lifetimes right.

I'm basically following https://michael-f-bryan.github.io/rust-ffi-guide/dynamic_loading.html for the general setup, however it seems as if the Plugin trait on that site is creating references with 'static lifetime from within a dynamically loaded plugin, and I'm a bit puzzled how that can be correct, given that the plugin is loaded and unloaded at runtime.

Example copied (and shortened) from the linked page:

pub trait Plugin: Any + Send + Sync {
    fn name(&self) -> &'static str;
    ...
}

With the library getting unloaded at runtime, both, the lifetime of the return value of fn name(&self) and the Any supertrait sound like a lie to me, at least if I understand correctly that unloading the library will remove all its "static" symbols from RAM and therefore making the string, the type id, etc. point to invalid memory...

The linked site even explicitly mentions that the loaded libraries need to stay in memory longer than the Plugin trait objects created from them, but the code seems not to enforce this in any way.

My naive idea to fix this was to just remove the Any trait (I don't need it), to tie all output references to the lifetime of self, and to also annotate the lifetime of the trait object in the return type of the function that creates the trait object from the library.

pub trait Plugin: Send {
    fn name<'p>(&'p self) -> &'p str;
    ...
}

pub fn load_plugin_from_library<'p>(&'p library : Library) -> Box<dyn Plugin + 'p> {
    ...
}

I think that this will make sure that on the calling side I cannot accidentally call any plugin methods after the library goes out of scope, however I just realized that there is nothing stopping the implementer of the plugin to accidentally reference the library even after the Plugin trait object has been dropped.

For instance, the fn name(&self) could internally just spawn a new thread and detach it. That thread could still rely on the library's symbols, and if it is still running when I unload the library everything will crash.

Now my actual question is, if I can somehow prevent this situation, other than marking the trait as unsafe to make sure implementers actually read the documentation to make sure all threads they spawn are joined before returning from the Plugin's methods?

0 Answers
Related