rust-lang / rust-lang/rust-bindgen

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

Open
#2,878 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the wrapper.h struct and the generated bindings shown in the issue, then run the provided cargo test reproduction. Check how bindgen represents packed and aligned C structs; done means the generated layout preserves field offsets 0 and 4 while retaining the expected size and alignment.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, cpp, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.