Michael-F-Bryan/rust-ffi-guide

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

ruifengx opened this issue · 0 comments

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.