diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2020-11-28 01:33:32 +0100 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2020-11-28 03:14:51 +0100 |
commit | 19142ac6b3d8ee4fc5686d6f30b77e660026e528 (patch) | |
tree | 7be336cb2bfd34e6a8c844b868efb4332aba9c4f /src/codegen/struct_layout.rs | |
parent | 6a5726eac514b49ec8a9f8360ed5d0d73da9feb7 (diff) |
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
Diffstat (limited to 'src/codegen/struct_layout.rs')
-rw-r--r-- | src/codegen/struct_layout.rs | 35 |
1 files changed, 24 insertions, 11 deletions
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<Layout>, latest_offset: usize, padding_count: usize, latest_field_layout: Option<Layout>, @@ -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: <padding>: {} -> {}", self.latest_offset - padding_bytes, |