diff options
author | Eric Seppanen <eds@reric.net> | 2021-07-16 12:22:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-16 21:22:02 +0200 |
commit | 67538b64ea1b90a0d01e4f6ebd45713ec03c9222 (patch) | |
tree | edde7c4ec2744b0221eebaea2e40125d9d441076 /src/codegen/struct_layout.rs | |
parent | 14a8d29baa1da364c6f33de42c4048ed573b06ed (diff) |
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.
Diffstat (limited to 'src/codegen/struct_layout.rs')
-rw-r--r-- | src/codegen/struct_layout.rs | 42 |
1 files changed, 37 insertions, 5 deletions
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<proc_macro2::TokenStream> { + // 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, |