Michael-F-Bryan / rust-ffi-guide

A guide for doing FFI using Rust
https://michael-f-bryan.github.io/rust-ffi-guide/
Creative Commons Zero v1.0 Universal
282 stars 18 forks source link

Regarding plugins: ABI of `dyn Trait` is unstable and using it across FFI boundary might be UB #81

Open ruifengx opened 2 years ago

ruifengx commented 2 years ago

According to your own article (I believe), ABI for dyn Trait objects is unstable, therefore the following use in this guide might be UB:

#[macro_export]
macro_rules! declare_plugin {
    ($plugin_type:ty, $constructor:path) => {
        #[no_mangle]
        pub extern "C" fn _plugin_create() -> *mut $crate::Plugin {
            // make sure the constructor is the correct type.
            let constructor: fn() -> $plugin_type = $constructor;

            let object = constructor();
            let boxed: Box<$crate::Plugin> = Box::new(object);
            Box::into_raw(boxed)
        }
    };
}

Note the use of *mut $crate::Plugin as the return type. In Rust 2018/2021, it should be *mut dyn $crate::Plugin because Plugin is a trait (instead of a type). And if the layout of trait objects were to change for building the plugin and the host program (though I doubt if this would ever happen), this would result in UB.

For solutions, it seems that abi_stable::sabi_trait could be a candidate, but it looks ad-hoc and pulls in a non-trivial amount of dependencies. Another way would be to just use the "manual vtable" approach mentioned in your blog, which requires some boilerplate, but looks good otherwise.