From 67538b64ea1b90a0d01e4f6ebd45713ec03c9222 Mon Sep 17 00:00:00 2001 From: Eric Seppanen Date: Fri, 16 Jul 2021 12:22:02 -0700 Subject: Allow explicit padding (#2060) If a struct needs to be serialized in its native format (padding bytes and all), for example writing it to a file or sending it on the network, then explicit padding fields are necessary, as anything reading the padding bytes of a struct may lead to Undefined Behavior. --- src/codegen/struct_layout.rs | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'src/codegen/struct_layout.rs') diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index 2e4b9735..1c6b977b 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -217,8 +217,11 @@ impl<'a> StructLayoutTracker<'a> { let padding_layout = if self.is_packed || is_union { None } else { + let force_padding = self.ctx.options().force_explicit_padding; + // Otherwise the padding is useless. - let need_padding = padding_bytes >= field_layout.align || + let need_padding = force_padding || + padding_bytes >= field_layout.align || field_layout.align > MAX_GUARANTEED_ALIGN; debug!( @@ -236,11 +239,14 @@ impl<'a> StructLayoutTracker<'a> { field_layout ); + let padding_align = if force_padding { + 1 + } else { + cmp::min(field_layout.align, MAX_GUARANTEED_ALIGN) + }; + if need_padding && padding_bytes != 0 { - Some(Layout::new( - padding_bytes, - cmp::min(field_layout.align, MAX_GUARANTEED_ALIGN), - )) + Some(Layout::new(padding_bytes, padding_align)) } else { None } @@ -262,6 +268,32 @@ impl<'a> StructLayoutTracker<'a> { padding_layout.map(|layout| self.padding_field(layout)) } + pub fn add_tail_padding( + &mut self, + comp_name: &str, + comp_layout: Layout, + ) -> Option { + // Only emit an padding field at the end of a struct if the + // user configures explicit padding. + if !self.ctx.options().force_explicit_padding { + return None; + } + + if self.latest_offset == comp_layout.size { + // This struct does not contain tail padding. + return None; + } + + trace!( + "need a tail padding field for {}: offset {} -> size {}", + comp_name, + self.latest_offset, + comp_layout.size + ); + let size = comp_layout.size - self.latest_offset; + Some(self.padding_field(Layout::new(size, 0))) + } + pub fn pad_struct( &mut self, layout: Layout, -- cgit v1.2.3