Skip to content

Cannot load library if new fields are added in sabi_trait trait #118

@SilverMira

Description

@SilverMira

Hello, I'm currently trying out this crate to implement a plugin system.

Although the docs seem to suggest that I can load a library that's compiled against a previous minor version of the shared interface, I'm getting a AbiInstability error when trying to load.

I'm not sure whether I'm doing anything wrong which made it not work.

// interface: 0.1.0
#[repr(u8)]
#[derive(StableAbi, Debug)]
#[sabi(kind(WithNonExhaustive(size = [usize; 8], traits(Debug))))]
#[non_exhaustive]
pub enum PluginError {
    NotSupported,
}

#[sabi_trait]
pub trait Plugin {
    #[sabi(last_prefix_field)]
    fn hello(&self, value: RStr<'_>) -> RResult<RString, NonExhaustiveFor<PluginError>> {
        RResult::RErr(NonExhaustiveFor::new(PluginError::NotSupported))
    }
}

pub type PluginBox = Plugin_TO<'static, RBox<()>>;


#[repr(C)]
#[derive(StableAbi)]
#[sabi(kind(Prefix(prefix_ref = PluginLibRef)))]
#[sabi(missing_field(panic))]
pub struct PluginLib {
    #[sabi(last_prefix_field)]
    pub new_plugin: extern "C" fn() -> PluginBox,
}

impl RootModule for PluginLibRef {
    abi_stable::declare_root_module_statics! {PluginLibRef}

    const BASE_NAME: &'static str = "plugin-interface";

    const NAME: &'static str = "plugin-interface";

    const VERSION_STRINGS: VersionStrings = package_version_strings!();
}

With the above interface crate, I'm able to compile and run hello() without issues. However if I update the Plugin trait as such and try to rebuild & run the main executable without recompiling the library, I'm getting a AbiInstability error "Too many fields" while loading the library.

// interface: 0.1.1 
#[sabi_trait]
pub trait Plugin {
    #[sabi(last_prefix_field)]
    fn hello(&self, value: RStr<'_>) -> RResult<RString, NonExhaustiveFor<PluginError>> {
        RResult::RErr(NonExhaustiveFor::new(PluginError::NotSupported))
    }
    fn not_implemented_yet(&self) -> RResult<RString, NonExhaustiveFor<PluginError>> {
        RResult::RErr(NonExhaustiveFor::new(PluginError::NotSupported))
    }
}
Logging the AbiInstability error
AbiInstability(Compared <this>:
    --- Type Layout ---
    type:PrefixRef<'a, PluginLib>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    line:392 mod:abi_stable::prefix_type::prefix_ref
    data:
        Struct with Fields:

    Phantom fields:

        field_name:0
        type:PluginLib
        size:8 align:8
        package:'interface' version:'0.1.1'Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:DelegateDeref { layout_index: 0 }
To <other>:
    --- Type Layout ---
    type:PrefixRef<'a, PluginLib>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    line:392 mod:abi_stable::prefix_type::prefix_ref
    data:
        Struct with Fields:

    Phantom fields:

        field_name:0
        type:PluginLib
        size:8 align:8
        package:'interface' version:'0.1.1'Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:DelegateDeref { layout_index: 0 }

0 error(s).

0 error(s)inside:
    <other>

    field_name:0
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'

Layout of expected type:
    --- Type Layout ---
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'
    line:12 mod:interface
    data:
        Prefix type:
        first_suffix_field:1
        conditional_prefix_fields:
            0
        fields:
            field_name:new_plugin
            type:AFunctionPointer
            size:8 align:8
            package:'abi_stable' version:'0.11.3'
            fn pointer(s):
                fn()->Plugin_TO<'lt>

        accessible_fields:
            [Yes]
    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:C
    Module reflection mode:Module

Layout of found type:
    --- Type Layout ---
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'
    line:12 mod:interface
    data:
        Prefix type:
        first_suffix_field:1
        conditional_prefix_fields:
            0
        fields:
            field_name:new_plugin
            type:AFunctionPointer
            size:8 align:8
            package:'abi_stable' version:'0.11.3'
            fn pointer(s):
                fn()->Plugin_TO<'lt>

        accessible_fields:
            [Yes]
    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:C
    Module reflection mode:Module


0 error(s)inside:
    <other>

    field_name:0
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'

    field_name:new_plugin
    type:AFunctionPointer
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    fn pointer(s):
        fn()->Plugin_TO<'lt>

    fn()->Plugin_TO<'lt>

    field_name:__returns
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'

Layout of expected type:
    --- Type Layout ---
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'
    line:38 mod:interface::Plugin_trait
    data:
        Struct with Fields:
            field_name:obj
            type:RObject<'lt>
            size:24 align:8
            package:'abi_stable' version:'0.11.3'
            lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

            field_name:_marker
            type:UnsafeIgnoredType
            size:0 align:1
            package:'abi_stable' version:'0.11.3'

    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:Module

Layout of found type:
    --- Type Layout ---
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'
    line:38 mod:interface::Plugin_trait
    data:
        Struct with Fields:
            field_name:obj
            type:RObject<'lt>
            size:24 align:8
            package:'abi_stable' version:'0.11.3'
            lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

            field_name:_marker
            type:UnsafeIgnoredType
            size:0 align:1
            package:'abi_stable' version:'0.11.3'

    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:Module


0 error(s)inside:
    <other>

    field_name:0
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'

    field_name:new_plugin
    type:AFunctionPointer
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    fn pointer(s):
        fn()->Plugin_TO<'lt>

    fn()->Plugin_TO<'lt>

    field_name:__returns
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'

    field_name:obj
    type:RObject<'lt>
    size:24 align:8
    package:'abi_stable' version:'0.11.3'
    lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

Layout of expected type:
    --- Type Layout ---
    type:RObject<'lt>
    size:24 align:8
    package:'abi_stable' version:'0.11.3'
    line:77 mod:abi_stable::sabi_trait::robject
    data:
        Struct with Fields:
            field_name:vtable
            type:PrefixRef<'a, VTable>
            size:8 align:8
            package:'abi_stable' version:'0.11.3'

            field_name:ptr
            type:ManuallyDrop<RBox>
            size:16 align:8
            package:'std' version:'1.0.0'

            field_name:_marker
            type:PhantomData<&'a  () , AFunctionPointer>
            size:0 align:1
            package:'std' version:'1.0.0'
            fn pointer(s):
                fn()->Plugin_Interface
            lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

    Tag:
        null
    Extra checks:
        RequiredTraits
        Auto traits:<no_traits>
        Impld traits:<no_traits>
    Repr attribute:C
    Module reflection mode:Opaque

Layout of found type:
    --- Type Layout ---
    type:RObject<'lt>
    size:24 align:8
    package:'abi_stable' version:'0.11.3'
    line:77 mod:abi_stable::sabi_trait::robject
    data:
        Struct with Fields:
            field_name:vtable
            type:PrefixRef<'a, VTable>
            size:8 align:8
            package:'abi_stable' version:'0.11.3'

            field_name:ptr
            type:ManuallyDrop<RBox>
            size:16 align:8
            package:'std' version:'1.0.0'

            field_name:_marker
            type:PhantomData<&'a  () , AFunctionPointer>
            size:0 align:1
            package:'std' version:'1.0.0'
            fn pointer(s):
                fn()->Plugin_Interface
            lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

    Tag:
        null
    Extra checks:
        RequiredTraits
        Auto traits:<no_traits>
        Impld traits:<no_traits>
    Repr attribute:C
    Module reflection mode:Opaque


0 error(s)inside:
    <other>

    field_name:0
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'

    field_name:new_plugin
    type:AFunctionPointer
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    fn pointer(s):
        fn()->Plugin_TO<'lt>

    fn()->Plugin_TO<'lt>

    field_name:__returns
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'

    field_name:obj
    type:RObject<'lt>
    size:24 align:8
    package:'abi_stable' version:'0.11.3'
    lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

    field_name:vtable
    type:PrefixRef<'a, VTable>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'

Layout of expected type:
    --- Type Layout ---
    type:PrefixRef<'a, VTable>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    line:392 mod:abi_stable::prefix_type::prefix_ref
    data:
        Struct with Fields:

    Phantom fields:

        field_name:0
        type:VTable
        size:16 align:8
        package:'interface' version:'0.1.1'Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:DelegateDeref { layout_index: 0 }

Layout of found type:
    --- Type Layout ---
    type:PrefixRef<'a, VTable>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    line:392 mod:abi_stable::prefix_type::prefix_ref
    data:
        Struct with Fields:

    Phantom fields:

        field_name:0
        type:VTable
        size:16 align:8
        package:'interface' version:'0.1.1'Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:Transparent
    Module reflection mode:DelegateDeref { layout_index: 0 }


1 error(s)inside:
    <other>

    field_name:0
    type:PluginLib
    size:8 align:8
    package:'interface' version:'0.1.1'

    field_name:new_plugin
    type:AFunctionPointer
    size:8 align:8
    package:'abi_stable' version:'0.11.3'
    fn pointer(s):
        fn()->Plugin_TO<'lt>

    fn()->Plugin_TO<'lt>

    field_name:__returns
    type:Plugin_TO<'lt>
    size:24 align:8
    package:'interface' version:'0.1.1'

    field_name:obj
    type:RObject<'lt>
    size:24 align:8
    package:'abi_stable' version:'0.11.3'
    lifetime indices:Array(ArrayLen { len: 1, array: [[Param(0), NONE], [NONE, NONE], [NONE, NONE]] })

    field_name:vtable
    type:PrefixRef<'a, VTable>
    size:8 align:8
    package:'abi_stable' version:'0.11.3'

    field_name:0
    type:VTable
    size:16 align:8
    package:'interface' version:'0.1.1'

Layout of expected type:
    --- Type Layout ---
    type:VTable
    size:16 align:8
    package:'interface' version:'0.1.1'
    line:38 mod:interface::Plugin_trait
    data:
        Prefix type:
        first_suffix_field:3
        conditional_prefix_fields:
            0
        fields:
            field_name:_sabi_tys
            type:PhantomData<(), RBox>
            size:0 align:1
            package:'std' version:'1.0.0'

            field_name:_sabi_vtable
            type:PrefixRef<'a, RObjectVtable>
            size:8 align:8
            package:'abi_stable' version:'0.11.3'

            field_name:hello
            type:AFunctionPointer
            size:8 align:8
            package:'abi_stable' version:'0.11.3'
            fn pointer(s):
                unsafe fn(_self,param_0,: RRef<'a>, param_1: RStr<'a>)->RResult
                lifetime indices:Array(ArrayLen { len: 1, array: [[ANONYMOUS, ANONYMOUS], [NONE, NONE], [NONE, NONE]] })

            field_name:not_implemented_yet
            type:AFunctionPointer
            size:8 align:8
            package:'abi_stable' version:'0.11.3'
            fn pointer(s):
                unsafe fn(_self,: RRef<'a>)->RResult
                lifetime indices:Array(ArrayLen { len: 1, array: [[ANONYMOUS, NONE], [NONE, NONE], [NONE, NONE]] })

        accessible_fields:
            [Yes, Yes, Yes, Yes]
    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:C
    Module reflection mode:Module

Layout of found type:
    --- Type Layout ---
    type:VTable
    size:16 align:8
    package:'interface' version:'0.1.1'
    line:38 mod:interface::Plugin_trait
    data:
        Prefix type:
        first_suffix_field:3
        conditional_prefix_fields:
            0
        fields:
            field_name:_sabi_tys
            type:PhantomData<(), RBox>
            size:0 align:1
            package:'std' version:'1.0.0'

            field_name:_sabi_vtable
            type:PrefixRef<'a, RObjectVtable>
            size:8 align:8
            package:'abi_stable' version:'0.11.3'

            field_name:hello
            type:AFunctionPointer
            size:8 align:8
            package:'abi_stable' version:'0.11.3'
            fn pointer(s):
                unsafe fn(_self,param_0,: RRef<'a>, param_1: RStr<'a>)->RResult
                lifetime indices:Array(ArrayLen { len: 1, array: [[ANONYMOUS, ANONYMOUS], [NONE, NONE], [NONE, NONE]] })

        accessible_fields:
            [Yes, Yes, Yes]
    Tag:
        null
    Extra checks:
        <nothing>
    Repr attribute:C
    Module reflection mode:Module



Error:too many fields
Expected:
    4
Found:
    3
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions