summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2020-11-28 01:33:32 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2020-11-28 03:14:51 +0100
commit19142ac6b3d8ee4fc5686d6f30b77e660026e528 (patch)
tree7be336cb2bfd34e6a8c844b868efb4332aba9c4f /src
parent6a5726eac514b49ec8a9f8360ed5d0d73da9feb7 (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')
-rw-r--r--src/codegen/mod.rs2
-rw-r--r--src/codegen/struct_layout.rs35
-rw-r--r--src/ir/comp.rs6
3 files changed, 28 insertions, 15 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 15aea22a..0d93c491 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1650,7 +1650,7 @@ impl CodeGenerator for CompInfo {
let ty = item.expect_type();
let layout = ty.layout(ctx);
- let mut packed = self.is_packed(ctx, &layout);
+ let mut packed = self.is_packed(ctx, layout.as_ref());
let canonical_name = item.canonical_name(ctx);
let canonical_ident = ctx.rust_ident(&canonical_name);
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,
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 22c124fa..1d257d20 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -1576,7 +1576,7 @@ impl CompInfo {
pub fn is_packed(
&self,
ctx: &BindgenContext,
- layout: &Option<Layout>,
+ layout: Option<&Layout>,
) -> bool {
if self.packed_attr {
return true;
@@ -1584,7 +1584,7 @@ impl CompInfo {
// Even though `libclang` doesn't expose `#pragma packed(...)`, we can
// detect it through its effects.
- if let Some(ref parent_layout) = *layout {
+ if let Some(parent_layout) = layout {
if self.fields().iter().any(|f| match *f {
Field::Bitfields(ref unit) => {
unit.layout().align > parent_layout.align
@@ -1739,7 +1739,7 @@ impl IsOpaque for CompInfo {
//
// See https://github.com/rust-lang/rust-bindgen/issues/537 and
// https://github.com/rust-lang/rust/issues/33158
- if self.is_packed(ctx, layout) &&
+ if self.is_packed(ctx, layout.as_ref()) &&
layout.map_or(false, |l| l.align > 1)
{
warn!("Found a type that is both packed and aligned to greater than \