summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/codegen/mod.rs8
-rw-r--r--src/codegen/struct_layout.rs42
-rw-r--r--src/lib.rs19
-rw-r--r--src/options.rs7
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,
diff --git a/src/lib.rs b/src/lib.rs
index 1ac053b7..1c51c8ae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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))