Skip to content

Conversation

loichyan
Copy link
Contributor

Motivation

This PR prevents users from using trait aliases to implement an interface. Although they rarely do so, it is indeed possible to write unsound code as illustrated below:

#[crate_interface::def_interface]
trait MyIf1 {
    fn foo() -> usize;
}

#[crate_interface::def_interface]
trait MyIf2 {
    fn foo() -> isize;
    //          ^^^^^ Use a slightly different signature
    //                to make the assertion safely passes.
}

const _: () = {
    use MyIf2 as MyIf1; // Alias MyIf2 to MyIf1
    struct MyImpl;
    #[crate_interface::impl_interface]
    impl MyIf1 for MyImpl {
        fn foo() -> isize { -1234 }
        // ^^^ It corresponds to an `extern fn` named `__MyIf_foo`,
        //     which is exactly what `call_interface!(MyIf1::foo)` invokes,
        //     but its return type is not `usize`!
    }
};

assert_eq!(crate_interface::call_interface!(MyIf1::foo), (-1234isize) as usize);

Implementation

The approach is rather straightforward, as illustrated below:

// #[crate_interface::def_interface]
trait MyIf1 {
    fn foo() -> usize;
    const __MustNotAnAlias__MyIf1: () = ();
    //    ^^^^^^^^^^^^^^^^^^^^^^^ An dummy item is appended to the trait definition;
    //                            it has a default value, so it's invisible for users.
}

use MyIf1 as MyIf2;
struct MyImpl;
// #[crate_interface::impl_interface]
impl MyIf2 for MyImpl {
    fn foo() -> usize { 1234 }
    const __MustNotAnAlias__MyIf2: () = ();
    //                      ^^^^^ This item does not exist in MyIf1,
    //                            resulting in a compile error.
}

@equation314 equation314 merged commit 9d16c20 into arceos-org:main Jun 1, 2025
9 checks passed
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

Successfully merging this pull request may close these issues.

2 participants