diff options
| author | Benno Lossin <lossin@kernel.org> | 2026-03-02 15:04:14 +0100 |
|---|---|---|
| committer | Miguel Ojeda <ojeda@kernel.org> | 2026-03-06 02:04:09 +0100 |
| commit | a075082a15e7f5c4889d0cbb51a4041c332cb00c (patch) | |
| tree | 162393ed6e76def1d8b43b3c17fbdc208ddcea20 /rust | |
| parent | dda135077ecc9f15c407f094dcfe7800376be867 (diff) | |
rust: pin-init: internal: init: remove `#[disable_initialized_field_access]`
Gary noticed [1] that the initializer macros as well as the `[Pin]Init`
traits cannot support unaligned fields, since they use operations that
require aligned pointers. This means that any code using structs with
unaligned fields in pin-init is unsound.
By default, the `init!` macro generates references to initialized fields,
which makes the compiler check that those fields are aligned. However,
we added the `#[disable_initialized_field_access]` attribute to avoid
this behavior in commit ceca298c53f9 ("rust: pin-init: internal: init:
add escape hatch for referencing initialized fields"). Thus remove the
`#[disable_initialized_field_access]` attribute from `init!`, which is
the only safe way to create an initializer handling unaligned fields.
If support for in-place initializing structs with unaligned fields is
required in the future, we could figure out a solution. This is tracked
in [2].
Reported-by: Gary Guo <gary@garyguo.net>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/561532-pin-init/topic/initialized.20field.20accessor.20detection/with/576210658 [1]
Link: https://github.com/Rust-for-Linux/pin-init/issues/112 [2]
Fixes: ceca298c53f9 ("rust: pin-init: internal: init: add escape hatch for referencing initialized fields")
Signed-off-by: Benno Lossin <lossin@kernel.org>
Acked-by: Janne Grunau <j@jannau.net>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://patch.msgid.link/20260302140424.4097655-1-lossin@kernel.org
[ Adjusted tags and reworded as discussed. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/pin-init/internal/src/init.rs | 39 |
1 files changed, 8 insertions, 31 deletions
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs index 42936f915a07..da53adc44ecf 100644 --- a/rust/pin-init/internal/src/init.rs +++ b/rust/pin-init/internal/src/init.rs @@ -62,7 +62,6 @@ impl InitializerKind { enum InitializerAttribute { DefaultError(DefaultErrorAttribute), - DisableInitializedFieldAccess, } struct DefaultErrorAttribute { @@ -86,6 +85,7 @@ pub(crate) fn expand( let error = error.map_or_else( || { if let Some(default_error) = attrs.iter().fold(None, |acc, attr| { + #[expect(irrefutable_let_patterns)] if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr { Some(ty.clone()) } else { @@ -145,15 +145,7 @@ pub(crate) fn expand( }; // `mixed_site` ensures that the data is not accessible to the user-controlled code. let data = Ident::new("__data", Span::mixed_site()); - let init_fields = init_fields( - &fields, - pinned, - !attrs - .iter() - .any(|attr| matches!(attr, InitializerAttribute::DisableInitializedFieldAccess)), - &data, - &slot, - ); + let init_fields = init_fields(&fields, pinned, &data, &slot); let field_check = make_field_check(&fields, init_kind, &path); Ok(quote! {{ // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return @@ -236,7 +228,6 @@ fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKi fn init_fields( fields: &Punctuated<InitializerField, Token![,]>, pinned: bool, - generate_initialized_accessors: bool, data: &Ident, slot: &Ident, ) -> TokenStream { @@ -272,13 +263,6 @@ fn init_fields( unsafe { &mut (*#slot).#ident } } }; - let accessor = generate_initialized_accessors.then(|| { - quote! { - #(#cfgs)* - #[allow(unused_variables)] - let #ident = #accessor; - } - }); quote! { #(#attrs)* { @@ -286,7 +270,9 @@ fn init_fields( // SAFETY: TODO unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) }; } - #accessor + #(#cfgs)* + #[allow(unused_variables)] + let #ident = #accessor; } } InitializerKind::Init { ident, value, .. } => { @@ -326,20 +312,15 @@ fn init_fields( }, ) }; - let accessor = generate_initialized_accessors.then(|| { - quote! { - #(#cfgs)* - #[allow(unused_variables)] - let #ident = #accessor; - } - }); quote! { #(#attrs)* { let #init = #value; #value_init } - #accessor + #(#cfgs)* + #[allow(unused_variables)] + let #ident = #accessor; } } InitializerKind::Code { block: value, .. } => quote! { @@ -466,10 +447,6 @@ impl Parse for Initializer { if a.path().is_ident("default_error") { a.parse_args::<DefaultErrorAttribute>() .map(InitializerAttribute::DefaultError) - } else if a.path().is_ident("disable_initialized_field_access") { - a.meta - .require_path_only() - .map(|_| InitializerAttribute::DisableInitializedFieldAccess) } else { Err(syn::Error::new_spanned(a, "unknown initializer attribute")) } |
