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.45k stars 694 forks source link

Incorrect field offset when C struct is __attribute__((packed, aligned(8))) #2878

Open kurtmcmillan opened 3 months ago

kurtmcmillan commented 3 months ago

Input C/C++ Header

struct foo
{
    int a;
    long b;
} __attribute__((packed, aligned(8)));

Bindgen Invocation

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");

Actual Results

$ RUST_BACKTRACE=1 cargo test
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running unittests src/lib.rs (target/debug/deps/bindgen-8ef8fba8e13f0c4e)

running 1 test
test bindings::bindgen_test_layout_foo ... FAILED

failures:

---- bindings::bindgen_test_layout_foo stdout ----
thread 'bindings::bindgen_test_layout_foo' panicked at /home/kumcmill/bindgen/target/debug/build/bindgen-7cb8e559bd3e3745/out/bindings.rs:28:5:
assertion `left == right` failed: Offset of field: foo::b
  left: 8
 right: 4
stack backtrace:
   0: rust_begin_unwind
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_fmt
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/core/src/panicking.rs:72:14
   2: core::panicking::assert_failed_inner
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/core/src/panicking.rs:403:23
   3: core::panicking::assert_failed
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/core/src/panicking.rs:363:5
   4: bindgen::bindings::bindgen_test_layout_foo
             at ./target/debug/build/bindgen-7cb8e559bd3e3745/out/bindings.rs:28:5
   5: bindgen::bindings::bindgen_test_layout_foo::{{closure}}
             at ./target/debug/build/bindgen-7cb8e559bd3e3745/out/bindings.rs:10:29
   6: core::ops::function::FnOnce::call_once
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/core/src/ops/function.rs:250:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

failures:
    bindings::bindgen_test_layout_foo

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s

and/or

/* automatically generated by rust-bindgen 0.69.4 */

#[repr(C, packed(8))]
#[derive(Debug, Copy, Clone)]
pub struct foo {
    pub a: ::std::os::raw::c_int,
    pub b: ::std::os::raw::c_long,
}
#[test]
fn bindgen_test_layout_foo() {
    const UNINIT: ::std::mem::MaybeUninit<foo> = ::std::mem::MaybeUninit::uninit();
    let ptr = UNINIT.as_ptr();
    assert_eq!(
        ::std::mem::size_of::<foo>(),
        16usize,
        concat!("Size of: ", stringify!(foo))
    );
    assert_eq!(
        ::std::mem::align_of::<foo>(),
        8usize,
        concat!("Alignment of ", stringify!(foo))
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).a) as usize - ptr as usize },
        0usize,
        concat!("Offset of field: ", stringify!(foo), "::", stringify!(a))
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize },
        4usize,
        concat!("Offset of field: ", stringify!(foo), "::", stringify!(b))
    );
}

Expected Results

A data structure with two fields. The first field at offset 0 and the second field at offset 4.

I initially filed this issue against rust-lang/rust (#128373). It turned out to be a duplicate of E0587 error on packed and aligned structures from C.

The suggestion from rust-lang/rust in #127373 was to file this against bindgen with the recommendation to handle this case by generating a packed inner struct wrapped in an align(8) outer struct.

pvdrz commented 2 weeks ago

Sounds like a duplicate of https://github.com/rust-lang/rust-bindgen/issues/2101