Skip to content

Commit 6733609

Browse files
nbdd0121gregkh
authored andcommitted
rust: pin-init: internal: move alignment check to make_field_check
commit 83ac287 upstream. Instead of having the reference creation serving dual-purpose as both for let bindings and alignment check, detangle them so that the alignment check is done explicitly in `make_field_check`. This is more robust against refactors that may change the way let bindings are created. Cc: stable@vger.kernel.org Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260427-pin-init-fix-v3-1-496a699674dd@garyguo.net [ Reworded for typo. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent aaf9af1 commit 6733609

1 file changed

Lines changed: 37 additions & 41 deletions

File tree

rust/pin-init/internal/src/init.rs

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,6 @@ fn init_fields(
243243
});
244244
// Again span for better diagnostics
245245
let write = quote_spanned!(ident.span()=> ::core::ptr::write);
246-
// NOTE: the field accessor ensures that the initialized field is properly aligned.
247-
// Unaligned fields will cause the compiler to emit E0793. We do not support
248-
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
249-
// `ptr::write` below has the same requirement.
250246
let accessor = if pinned {
251247
let project_ident = format_ident!("__project_{ident}");
252248
quote! {
@@ -361,49 +357,49 @@ fn init_fields(
361357
}
362358
}
363359

364-
/// Generate the check for ensuring that every field has been initialized.
360+
/// Generate the check for ensuring that every field has been initialized and aligned.
365361
fn make_field_check(
366362
fields: &Punctuated<InitializerField, Token![,]>,
367363
init_kind: InitKind,
368364
path: &Path,
369365
) -> TokenStream {
370-
let field_attrs = fields
366+
let field_attrs: Vec<_> = fields
371367
.iter()
372-
.filter_map(|f| f.kind.ident().map(|_| &f.attrs));
373-
let field_name = fields.iter().filter_map(|f| f.kind.ident());
374-
match init_kind {
375-
InitKind::Normal => quote! {
376-
// We use unreachable code to ensure that all fields have been mentioned exactly once,
377-
// this struct initializer will still be type-checked and complain with a very natural
378-
// error message if a field is forgotten/mentioned more than once.
379-
#[allow(unreachable_code, clippy::diverging_sub_expression)]
380-
// SAFETY: this code is never executed.
381-
let _ = || unsafe {
382-
::core::ptr::write(slot, #path {
383-
#(
384-
#(#field_attrs)*
385-
#field_name: ::core::panic!(),
386-
)*
387-
})
388-
};
389-
},
390-
InitKind::Zeroing => quote! {
391-
// We use unreachable code to ensure that all fields have been mentioned at most once.
392-
// Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
393-
// be zeroed. This struct initializer will still be type-checked and complain with a
394-
// very natural error message if a field is mentioned more than once, or doesn't exist.
395-
#[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
396-
// SAFETY: this code is never executed.
397-
let _ = || unsafe {
398-
::core::ptr::write(slot, #path {
399-
#(
400-
#(#field_attrs)*
401-
#field_name: ::core::panic!(),
402-
)*
403-
..::core::mem::zeroed()
404-
})
405-
};
406-
},
368+
.filter_map(|f| f.kind.ident().map(|_| &f.attrs))
369+
.collect();
370+
let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.ident()).collect();
371+
let zeroing_trailer = match init_kind {
372+
InitKind::Normal => None,
373+
InitKind::Zeroing => Some(quote! {
374+
..::core::mem::zeroed()
375+
}),
376+
};
377+
quote! {
378+
#[allow(unreachable_code, clippy::diverging_sub_expression)]
379+
// We use unreachable code to perform field checks. They're still checked by the compiler.
380+
// SAFETY: this code is never executed.
381+
let _ = || unsafe {
382+
// Create references to ensure that the initialized field is properly aligned.
383+
// Unaligned fields will cause the compiler to emit E0793. We do not support
384+
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
385+
// `ptr::write` for value-initialization case has the same requirement.
386+
#(
387+
#(#field_attrs)*
388+
let _ = &(*slot).#field_name;
389+
)*
390+
391+
// If the zeroing trailer is not present, this checks that all fields have been
392+
// mentioned exactly once. If the zeroing trailer is present, all missing fields will be
393+
// zeroed, so this checks that all fields have been mentioned at most once. The use of
394+
// struct initializer will still generate very natural error messages for any misuse.
395+
::core::ptr::write(slot, #path {
396+
#(
397+
#(#field_attrs)*
398+
#field_name: ::core::panic!(),
399+
)*
400+
#zeroing_trailer
401+
})
402+
};
407403
}
408404
}
409405

0 commit comments

Comments
 (0)