Skip to content

Commit a075082

Browse files
BennoLossinojeda
authored andcommitted
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 ceca298 ("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: Rust-for-Linux/pin-init#112 [2] Fixes: ceca298 ("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>
1 parent dda1350 commit a075082

1 file changed

Lines changed: 8 additions & 31 deletions

File tree

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

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ impl InitializerKind {
6262

6363
enum InitializerAttribute {
6464
DefaultError(DefaultErrorAttribute),
65-
DisableInitializedFieldAccess,
6665
}
6766

6867
struct DefaultErrorAttribute {
@@ -86,6 +85,7 @@ pub(crate) fn expand(
8685
let error = error.map_or_else(
8786
|| {
8887
if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
88+
#[expect(irrefutable_let_patterns)]
8989
if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
9090
Some(ty.clone())
9191
} else {
@@ -145,15 +145,7 @@ pub(crate) fn expand(
145145
};
146146
// `mixed_site` ensures that the data is not accessible to the user-controlled code.
147147
let data = Ident::new("__data", Span::mixed_site());
148-
let init_fields = init_fields(
149-
&fields,
150-
pinned,
151-
!attrs
152-
.iter()
153-
.any(|attr| matches!(attr, InitializerAttribute::DisableInitializedFieldAccess)),
154-
&data,
155-
&slot,
156-
);
148+
let init_fields = init_fields(&fields, pinned, &data, &slot);
157149
let field_check = make_field_check(&fields, init_kind, &path);
158150
Ok(quote! {{
159151
// 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
236228
fn init_fields(
237229
fields: &Punctuated<InitializerField, Token![,]>,
238230
pinned: bool,
239-
generate_initialized_accessors: bool,
240231
data: &Ident,
241232
slot: &Ident,
242233
) -> TokenStream {
@@ -272,21 +263,16 @@ fn init_fields(
272263
unsafe { &mut (*#slot).#ident }
273264
}
274265
};
275-
let accessor = generate_initialized_accessors.then(|| {
276-
quote! {
277-
#(#cfgs)*
278-
#[allow(unused_variables)]
279-
let #ident = #accessor;
280-
}
281-
});
282266
quote! {
283267
#(#attrs)*
284268
{
285269
#value_prep
286270
// SAFETY: TODO
287271
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
288272
}
289-
#accessor
273+
#(#cfgs)*
274+
#[allow(unused_variables)]
275+
let #ident = #accessor;
290276
}
291277
}
292278
InitializerKind::Init { ident, value, .. } => {
@@ -326,20 +312,15 @@ fn init_fields(
326312
},
327313
)
328314
};
329-
let accessor = generate_initialized_accessors.then(|| {
330-
quote! {
331-
#(#cfgs)*
332-
#[allow(unused_variables)]
333-
let #ident = #accessor;
334-
}
335-
});
336315
quote! {
337316
#(#attrs)*
338317
{
339318
let #init = #value;
340319
#value_init
341320
}
342-
#accessor
321+
#(#cfgs)*
322+
#[allow(unused_variables)]
323+
let #ident = #accessor;
343324
}
344325
}
345326
InitializerKind::Code { block: value, .. } => quote! {
@@ -466,10 +447,6 @@ impl Parse for Initializer {
466447
if a.path().is_ident("default_error") {
467448
a.parse_args::<DefaultErrorAttribute>()
468449
.map(InitializerAttribute::DefaultError)
469-
} else if a.path().is_ident("disable_initialized_field_access") {
470-
a.meta
471-
.require_path_only()
472-
.map(|_| InitializerAttribute::DisableInitializedFieldAccess)
473450
} else {
474451
Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
475452
}

0 commit comments

Comments
 (0)