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 | |
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')
-rw-r--r-- | src/codegen/mod.rs | 8 | ||||
-rw-r--r-- | src/codegen/struct_layout.rs | 42 | ||||
-rw-r--r-- | src/lib.rs | 19 | ||||
-rw-r--r-- | src/options.rs | 7 |
4 files changed, 71 insertions, 5 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6f8a451a..515ebf17 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1797,6 +1797,14 @@ impl CodeGenerator for CompInfo { (), ); } + // Check whether an explicit padding field is needed + // at the end. + if let Some(comp_layout) = layout { + fields.extend( + struct_layout + .add_tail_padding(&canonical_name, comp_layout), + ); + } } if is_opaque { 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, @@ -562,6 +562,10 @@ impl Builder { output_vector.push("--c-naming".into()); } + if self.options.force_explicit_padding { + output_vector.push("--explicit-padding".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1419,6 +1423,17 @@ impl Builder { self } + /// If true, always emit explicit padding fields. + /// + /// 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 this should be enabled, as anything reading the padding bytes of + /// a struct may lead to Undefined Behavior. + pub fn explicit_padding(mut self, doit: bool) -> Self { + self.options.force_explicit_padding = doit; + self + } + /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result<Bindings, ()> { // Add any extra arguments from the environment to the clang command line. @@ -1937,6 +1952,9 @@ struct BindgenOptions { /// Generate types with C style naming. c_naming: bool, + + /// Always output explicit padding fields + force_explicit_padding: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -2079,6 +2097,7 @@ impl Default for BindgenOptions { respect_cxx_access_specs: false, translate_enum_integer_types: false, c_naming: false, + force_explicit_padding: false, } } } diff --git a/src/options.rs b/src/options.rs index cbdc945e..eeeb5aae 100644 --- a/src/options.rs +++ b/src/options.rs @@ -516,6 +516,9 @@ where Arg::with_name("c-naming") .long("c-naming") .help("Generate types with C style naming."), + Arg::with_name("explicit-padding") + .long("explicit-padding") + .help("Always output explicit padding fields."), ]) // .args() .get_matches_from(args); @@ -960,6 +963,10 @@ where builder = builder.c_naming(true); } + if matches.is_present("explicit-padding") { + builder = builder.explicit_padding(true); + } + let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) |