Skip to content

Struct not packed when pragma pack is used #2067

Closed
@thburghout

Description

@thburghout

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
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions