rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.38k stars 689 forks source link

Bindgen produces incorrect bindings to functions with 80-bit long doubles (f80) #2378

Open GKFX opened 1 year ago

GKFX commented 1 year ago

Input C

// float_to_ld.h
long double float_to_ld(float f);

// float_to_ld.c
void test1(void);

long double float_to_ld(float f) {
    return f;
}

int main() {
    test1();
    return 0;
}

Bindgen Invocation

bindgen float_to_ld.h

Actual Results

extern "C" {
    pub fn float_to_ld(f: f32) -> u128;
}

#[no_mangle]
extern "C" fn test1() {
    let mut buf = [0; 10];
    for (i, x) in buf.iter_mut().enumerate() {
        *x ^= unsafe {
            float_to_ld(i as f32)
        };
    }
    println!("{buf:X?}");
}
[7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824, 7FFDF7F781F800005568AD1E4824]

This code fills up and overflows the x87 floating point stack, which doesn't crash the application but results in the stack containing nonsense values rather than the values 8.0, 9.0 expected. (This can be observed with gdb -ex start -ex 'layout asm' -ex 'tui reg float' float_to_ld.) Also the return values in the buffer are not the actual return values of the function as the wrong registers are being used.

As a more minor annoyance, even if the functions aren't used, rustc emits the warning note: 128-bit integers don't currently have a known stable ABI.

Expected Results

Either no bindings should be generated, or inline wrapper functions using inline assembly should be generated which correctly implement the calling convention. Given that Rust has no support for f80, simply omitting the bindings seems like the most pragmatic solution.

pvdrz commented 1 year ago

Hmmm... interesting. Could it be that we're assuming that float is f32 everywhere? I'll try to check this.

pvdrz commented 1 year ago

Related to https://github.com/rust-lang/rust-bindgen/issues/1851