Skip to content

#[no_mangle] is silently ignored on generic functions #26753

Closed
@jashank

Description

@jashank

A grossly simplified illustrative example.

Assume we're in a library crate (I want to get a shared object out of this so I'm using --crate-type dylib but this appears to be a problem for the general case), and we have the following items defined.

pub enum Action {
    Thing,
    OtherThing,
}

pub trait Game {
    fn legal_action_p(&self, a: &Action) -> bool;
}

If we now wish to expose a function that uses a Game implementor across the library boundary (if, for example, you wish to dlopen(3) then dlsym(3) it), one might expect that they could define a trait bound:

#[no_mangle]
pub extern fn decide_action<T: Game>(g: &T) -> () {
    println!("deciding action!");
    let a = Action::Thing;
    g.legal_action_p(&a);
}

(There's a reason I stuffed a println! in there.)

Compile: rustc testlib.rs --crate-type dylib -g --out-dir target/debug, then:

$ nm target/debug/libtestlib.so | grep -i decide_action
00000000003c5110 D _ZN13decide_action15__STATIC_FMTSTR20h722c5e523a62788eMaaE

Which is, of course, the println! format string. Note a lack of any symbol matching the exact name decide_action.

OK, but if we put the Game impl in a Box:

#[no_mangle]
pub extern fn decide_action(g: &Box<Game>) -> () {
    println!("deciding action!");
    let a = Action::Thing;
    (*g).legal_action_p(&a);
}

Suddenly, it comes back!

$ nm target/debug/libtestlib.so | grep -i decide_action
00000000000ad4b0 T decide_action
00000000000ad4f0 t _ZN13decide_action10__rust_abiE
00000000003c5120 d _ZN13decide_action15__STATIC_FMTSTR20hbe3d66b5baeedebcsbaE

gah!

This presents on stable, beta, and nightly.

This strikes me as a bug, although I'm not sure what in. I suppose you cannot really enforce traits across the extern boundary (although that would be Nice To Have if there's Rust on the other side). On the other hand, how does a box of trait somehow manage to subvert this? I supose this is a compiler error, but I'm a bit fuzzy about what the error is (I guess that if extern fn, then if trait bound, then fail, else do the extern fn).

(As a general note, "FFI" from Rust to Rust, where you explicitly want to plug dylibs, is substantially more uncomfortable than expected.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions