From e0fc5ca733521dcd926f9de6e17ba4dc3304da25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 10 Jul 2019 20:45:30 +0200 Subject: [PATCH] ir: Properly find the layout of incomplete arrays. So as to not pad stuff incorrectly, or needlessly add extra alignment, for example. Fixes #1589 --- src/ir/ty.rs | 6 + .../tests/incomplete-array-padding.rs | 173 ++++++++++++++++++ tests/expectations/tests/layout_align.rs | 1 - tests/expectations/tests/zero-sized-array.rs | 2 +- tests/headers/incomplete-array-padding.h | 4 + 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 tests/expectations/tests/incomplete-array-padding.rs create mode 100644 tests/headers/incomplete-array-padding.h diff --git a/src/ir/ty.rs b/src/ir/ty.rs index f54d476066..625b5f8741 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -249,6 +249,12 @@ impl Type { self.layout.or_else(|| { match self.kind { TypeKind::Comp(ref ci) => ci.layout(ctx), + TypeKind::Array(inner, length) if length == 0 => { + Some(Layout::new( + 0, + ctx.resolve_type(inner).layout(ctx)?.align, + )) + } // FIXME(emilio): This is a hack for anonymous union templates. // Use the actual pointer size! TypeKind::Pointer(..) => { diff --git a/tests/expectations/tests/incomplete-array-padding.rs b/tests/expectations/tests/incomplete-array-padding.rs new file mode 100644 index 0000000000..5e96bbce96 --- /dev/null +++ b/tests/expectations/tests/incomplete-array-padding.rs @@ -0,0 +1,173 @@ +/* automatically generated by rust-bindgen */ + +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, + align: [Align; 0], +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage, align: [] } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); +impl __IncompleteArrayField { + #[inline] + pub const fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData, []) + } + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} +impl ::std::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} +#[repr(C)] +#[derive(Debug)] +pub struct foo { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>, + pub b: __IncompleteArrayField<*mut ::std::os::raw::c_void>, +} +#[test] +fn bindgen_test_layout_foo() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(foo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(foo)) + ); +} +impl Default for foo { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl foo { + #[inline] + pub fn a(&self) -> ::std::os::raw::c_char { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) } + } + #[inline] + pub fn set_a(&mut self, val: ::std::os::raw::c_char) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1(a: ::std::os::raw::c_char) -> __BindgenBitfieldUnit<[u8; 1usize], u8> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize], u8> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let a: u8 = unsafe { ::std::mem::transmute(a) }; + a as u64 + }); + __bindgen_bitfield_unit + } +} diff --git a/tests/expectations/tests/layout_align.rs b/tests/expectations/tests/layout_align.rs index ea41b08fe5..51fa1d1a36 100644 --- a/tests/expectations/tests/layout_align.rs +++ b/tests/expectations/tests/layout_align.rs @@ -125,7 +125,6 @@ impl ::std::clone::Clone for __IncompleteArrayField { } } #[repr(C)] -#[repr(align(8))] #[derive(Debug)] pub struct rte_kni_fifo { ///< Next position to be written diff --git a/tests/expectations/tests/zero-sized-array.rs b/tests/expectations/tests/zero-sized-array.rs index a1ad22d665..c0b989c8e3 100644 --- a/tests/expectations/tests/zero-sized-array.rs +++ b/tests/expectations/tests/zero-sized-array.rs @@ -122,7 +122,7 @@ fn bindgen_test_layout_InheritsZeroSizedArray() { ); } /// And this should not get an `_address` field either. -#[repr(C, packed)] +#[repr(C)] #[derive(Debug, Default)] pub struct DynamicallySizedArray { pub arr: __IncompleteArrayField<::std::os::raw::c_char>, diff --git a/tests/headers/incomplete-array-padding.h b/tests/headers/incomplete-array-padding.h new file mode 100644 index 0000000000..3fcc4c1a09 --- /dev/null +++ b/tests/headers/incomplete-array-padding.h @@ -0,0 +1,4 @@ +struct foo { + char a : 1; + void *b[]; +};