Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struct not packed when pragma pack is used #2067

Closed
thburghout opened this issue Jun 18, 2021 · 2 comments
Closed

Struct not packed when pragma pack is used #2067

thburghout opened this issue Jun 18, 2021 · 2 comments

Comments

@thburghout
Copy link

Input C/C++ Header

#pragma pack(push, 1)
struct Struct {
    unsigned char a : 1;
    unsigned char b : 1;
    unsigned char c : 6;
    unsigned short int d : 16;
    unsigned char e : 8;
};
#pragma pack(pop)

Bindgen Invocation

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

Actual Results

#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
pub struct Struct {
    pub _bitfield_align_1: [u16; 0],
    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 5usize]>,
}
#[test]
fn bindgen_test_layout_Struct() {
    assert_eq!(
        ::std::mem::size_of::<Struct>(),
        4usize,
        concat!("Size of: ", stringify!(Struct))
    );
    assert_eq!(
        ::std::mem::align_of::<Struct>(),
        1usize,
        concat!("Alignment of ", stringify!(Struct))
    );
}
impl Struct {
    #[inline]
    pub fn a(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) }
    }
    #[inline]
    pub fn set_a(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(0usize, 1u8, val as u64)
        }
    }
    #[inline]
    pub fn b(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u8) }
    }
    #[inline]
    pub fn set_b(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(1usize, 1u8, val as u64)
        }
    }
    #[inline]
    pub fn c(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(2usize, 6u8) as u8) }
    }
    #[inline]
    pub fn set_c(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(2usize, 6u8, val as u64)
        }
    }
    #[inline]
    pub fn d(&self) -> ::std::os::raw::c_ushort {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 16u8) as u16) }
    }
    #[inline]
    pub fn set_d(&mut self, val: ::std::os::raw::c_ushort) {
        unsafe {
            let val: u16 = ::std::mem::transmute(val);
            self._bitfield_1.set(16usize, 16u8, val as u64)
        }
    }
    #[inline]
    pub fn e(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(32usize, 8u8) as u8) }
    }
    #[inline]
    pub fn set_e(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(32usize, 8u8, val as u64)
        }
    }
    #[inline]
    pub fn new_bitfield_1(
        a: ::std::os::raw::c_uchar,
        b: ::std::os::raw::c_uchar,
        c: ::std::os::raw::c_uchar,
        d: ::std::os::raw::c_ushort,
        e: ::std::os::raw::c_uchar,
    ) -> __BindgenBitfieldUnit<[u8; 5usize]> {
        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 5usize]> = Default::default();
        __bindgen_bitfield_unit.set(0usize, 1u8, {
            let a: u8 = unsafe { ::std::mem::transmute(a) };
            a as u64
        });
        __bindgen_bitfield_unit.set(1usize, 1u8, {
            let b: u8 = unsafe { ::std::mem::transmute(b) };
            b as u64
        });
        __bindgen_bitfield_unit.set(2usize, 6u8, {
            let c: u8 = unsafe { ::std::mem::transmute(c) };
            c as u64
        });
        __bindgen_bitfield_unit.set(16usize, 16u8, {
            let d: u16 = unsafe { ::std::mem::transmute(d) };
            d as u64
        });
        __bindgen_bitfield_unit.set(32usize, 8u8, {
            let e: u8 = unsafe { ::std::mem::transmute(e) };
            e as u64
        });
        __bindgen_bitfield_unit
    }
}

and/or

running 1 test
test bindgen_test_layout___fsid_t ... ok
test bindgen_test_layout_Struct ... FAILED

failures:

---- bindgen_test_layout_Struct stdout ----
thread 'bindgen_test_layout_Struct' panicked at 'assertion failed: `(left == right)`
  left: `5`,
 right: `4`: Size of: Struct', /home/thomas.burghout/Documents/impinj-e710/target/debug/build/mwe-47b414b04acb1316/out/bindings.rs:289:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    bindgen_test_layout_Struct

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

Expected Results

I expect a Rust struct with a bitfield of size 4 ([u8; 4usize]) instead of 5, with correct accessors for all fields. It is worth noting that using __attribute__((packed)) over #pragma pack(push, 1) does yield the correct results (and passing tests).

#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
pub struct Struct {
    pub _bitfield_align_1: [u8; 0],
    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>,
}
#[test]
fn bindgen_test_layout_Struct() {
    assert_eq!(
        ::std::mem::size_of::<Struct>(),
        4usize,
        concat!("Size of: ", stringify!(Struct))
    );
    assert_eq!(
        ::std::mem::align_of::<Struct>(),
        1usize,
        concat!("Alignment of ", stringify!(Struct))
    );
}
impl Struct {
    #[inline]
    pub fn a(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) }
    }
    #[inline]
    pub fn set_a(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(0usize, 1u8, val as u64)
        }
    }
    #[inline]
    pub fn b(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u8) }
    }
    #[inline]
    pub fn set_b(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(1usize, 1u8, val as u64)
        }
    }
    #[inline]
    pub fn c(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(2usize, 6u8) as u8) }
    }
    #[inline]
    pub fn set_c(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(2usize, 6u8, val as u64)
        }
    }
    #[inline]
    pub fn d(&self) -> ::std::os::raw::c_ushort {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 16u8) as u16) }
    }
    #[inline]
    pub fn set_d(&mut self, val: ::std::os::raw::c_ushort) {
        unsafe {
            let val: u16 = ::std::mem::transmute(val);
            self._bitfield_1.set(8usize, 16u8, val as u64)
        }
    }
    #[inline]
    pub fn e(&self) -> ::std::os::raw::c_uchar {
        unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 8u8) as u8) }
    }
    #[inline]
    pub fn set_e(&mut self, val: ::std::os::raw::c_uchar) {
        unsafe {
            let val: u8 = ::std::mem::transmute(val);
            self._bitfield_1.set(24usize, 8u8, val as u64)
        }
    }
    #[inline]
    pub fn new_bitfield_1(
        a: ::std::os::raw::c_uchar,
        b: ::std::os::raw::c_uchar,
        c: ::std::os::raw::c_uchar,
        d: ::std::os::raw::c_ushort,
        e: ::std::os::raw::c_uchar,
    ) -> __BindgenBitfieldUnit<[u8; 4usize]> {
        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default();
        __bindgen_bitfield_unit.set(0usize, 1u8, {
            let a: u8 = unsafe { ::std::mem::transmute(a) };
            a as u64
        });
        __bindgen_bitfield_unit.set(1usize, 1u8, {
            let b: u8 = unsafe { ::std::mem::transmute(b) };
            b as u64
        });
        __bindgen_bitfield_unit.set(2usize, 6u8, {
            let c: u8 = unsafe { ::std::mem::transmute(c) };
            c as u64
        });
        __bindgen_bitfield_unit.set(8usize, 16u8, {
            let d: u16 = unsafe { ::std::mem::transmute(d) };
            d as u64
        });
        __bindgen_bitfield_unit.set(24usize, 8u8, {
            let e: u8 = unsafe { ::std::mem::transmute(e) };
            e as u64
        });
        __bindgen_bitfield_unit
    }
}
@emilio
Copy link
Contributor

emilio commented Jun 21, 2021

I put up a fix here: #2068. The issue is basically this one, which only looks at the packed attribute:

rust-bindgen/src/ir/comp.rs

Lines 1631 to 1633 in b60339e

// TODO(emilio): If we could detect #pragma packed here we'd fix layout
// tests in divide-by-zero-in-struct-layout.rs
self.fields.compute_bitfield_units(ctx, self.packed_attr)

@emilio emilio closed this as completed in 14a8d29 Jun 21, 2021
@thburghout
Copy link
Author

Thank you! This indeed solved the issue.

LoganBarnett pushed a commit to LoganBarnett/rust-bindgen that referenced this issue Dec 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants