From 19142ac6b3d8ee4fc5686d6f30b77e660026e528 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sat, 28 Nov 2020 01:33:32 +0100 Subject: struct_layout: Fix field offset computation for packed(n) structs. This can cause unnecessary padding to be computed otherwise at the end of the struct. With repr(packed(n)), a field can have padding to adjacent fields as long as its alignment is less than n. So reuse the code we have to align to a field layout, aligning to the struct layout instead. Fixes #1934 --- src/codegen/struct_layout.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'src/codegen/struct_layout.rs') diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index 54dfd86e..4536e889 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -18,6 +18,7 @@ pub struct StructLayoutTracker<'a> { ctx: &'a BindgenContext, comp: &'a CompInfo, is_packed: bool, + known_type_layout: Option, latest_offset: usize, padding_count: usize, latest_field_layout: Option, @@ -86,11 +87,14 @@ impl<'a> StructLayoutTracker<'a> { ty: &'a Type, name: &'a str, ) -> Self { + let known_type_layout = ty.layout(ctx); + let is_packed = comp.is_packed(ctx, known_type_layout.as_ref()); StructLayoutTracker { name, ctx, comp, - is_packed: comp.is_packed(ctx, &ty.layout(ctx)), + is_packed, + known_type_layout, latest_offset: 0, padding_count: 0, latest_field_layout: None, @@ -180,23 +184,32 @@ impl<'a> StructLayoutTracker<'a> { let will_merge_with_bitfield = self.align_to_latest_field(field_layout); + let padding_bytes = match field_offset { + Some(offset) if offset / 8 > self.latest_offset => { + offset / 8 - self.latest_offset + } + _ => { + if will_merge_with_bitfield || field_layout.align == 0 { + 0 + } else if !self.is_packed { + self.padding_bytes(field_layout) + } else if let Some(l) = self.known_type_layout { + self.padding_bytes(l) + } else { + 0 + } + } + }; + + self.latest_offset += padding_bytes; + let padding_layout = if self.is_packed { None } else { - let padding_bytes = match field_offset { - Some(offset) if offset / 8 > self.latest_offset => { - offset / 8 - self.latest_offset - } - _ if will_merge_with_bitfield || field_layout.align == 0 => 0, - _ => self.padding_bytes(field_layout), - }; - // Otherwise the padding is useless. let need_padding = padding_bytes >= field_layout.align || field_layout.align > MAX_GUARANTEED_ALIGN; - self.latest_offset += padding_bytes; - debug!( "Offset: : {} -> {}", self.latest_offset - padding_bytes, -- cgit v1.2.3