summaryrefslogtreecommitdiff
path: root/src/codegen/struct_layout.rs
diff options
context:
space:
mode:
authorEric Seppanen <eds@reric.net>2021-07-16 12:22:02 -0700
committerGitHub <noreply@github.com>2021-07-16 21:22:02 +0200
commit67538b64ea1b90a0d01e4f6ebd45713ec03c9222 (patch)
treeedde7c4ec2744b0221eebaea2e40125d9d441076 /src/codegen/struct_layout.rs
parent14a8d29baa1da364c6f33de42c4048ed573b06ed (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.rs42
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,