简体   繁体   中英

Calling Rust function with function parameter from C results in SegFault

I build a shared object with Rust and link against it in C. Compiling/Linking works fine but as soon as I call the function I get a SegFault.

Rust function declaration: It consumes two integers/usize and a reference to a function that returns an integer/usize.

#[no_mangle]
pub fn show_loading_animation(from: usize,
                              to: usize,
                              progress_in_percentage_fn: &dyn Fn() -> usize) { ... }

I call it from C like this:

typedef long long usize; // 64 bit
extern void show_loading_animation(usize, usize, usize (*prog_fn)());

usize progress_reporter() {
    return 80l;
}

int main(void) {
    show_loading_animation(0, 100, &progress_reporter);
    return 0;
}

I assume &dyn Fn() is not compatible with a c function reference? I debugged into show_loading_animation with gdb. This is the assembly and the last line is where it crashes.

0000000000004530 <show_loading_animation>:
4530:       55                      push   %rbp
4531:       41 57                   push   %r15
4533:       41 56                   push   %r14
4535:       41 55                   push   %r13
4537:       41 54                   push   %r12
4539:       53                      push   %rbx
453a:       48 81 ec f8 00 00 00    sub    $0xf8,%rsp
4541:       48 89 94 24 e0 00 00    mov    %rdx,0xe0(%rsp)
4548:       00 
4549:       48 89 34 24             mov    %rsi,(%rsp)
454d:       48 39 fe                cmp    %rdi,%rsi
4550:       0f 82 a9 03 00 00       jb     48ff <show_loading_animation+0x3cf>
4556:       48 89 fb                mov    %rdi,%rbx
4559:       48 8b 41 18             mov    0x18(%rcx),%rax
455d:       48 89 84 24 d8 00 00    mov    %rax,0xd8(%rsp)
4564:       00 
4565:       45 31 f6                xor    %r14d,%r14d
4568:       48 8d 6c 24 30          lea    0x30(%rsp),%rbp
456d:       0f 1f 00                nopl   (%rax)
4570:       48 8b bc 24 e0 00 00    mov    0xe0(%rsp),%rdi
4577:       00 
4578:       ff 94 24 d8 00 00 00    callq  *0xd8(%rsp) <-- crash

&dyn T is a fat pointer (basically a pointer to data and a pointer to vtable), C knows nothing about it internal structure so you need to use type Fn = extern "C" fn() -> usize instead.

I could solve it this way. I provide two functions now, one for rust, one for FFI.

// translates extern c function reference to closure function for rust
#[no_mangle]
pub fn show_loading_animation_ffi(from: usize,
                                  to: usize,
                                  progress_in_percentage_fn: extern "C" fn() -> usize) {
    let fn_closure = || {
        progress_in_percentage_fn()
    };
    show_loading_animation(from, to, &fn_closure);
}

I removed #[no_mangle] from the pure rust function (see code above).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM