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 commitceca298c53("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:ceca298c53("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>
This commit is contained in:
parent
dda135077e
commit
a075082a15
|
|
@ -62,7 +62,6 @@ impl InitializerKind {
|
||||||
|
|
||||||
enum InitializerAttribute {
|
enum InitializerAttribute {
|
||||||
DefaultError(DefaultErrorAttribute),
|
DefaultError(DefaultErrorAttribute),
|
||||||
DisableInitializedFieldAccess,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultErrorAttribute {
|
struct DefaultErrorAttribute {
|
||||||
|
|
@ -86,6 +85,7 @@ pub(crate) fn expand(
|
||||||
let error = error.map_or_else(
|
let error = error.map_or_else(
|
||||||
|| {
|
|| {
|
||||||
if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
|
if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
|
||||||
|
#[expect(irrefutable_let_patterns)]
|
||||||
if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
|
if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
|
||||||
Some(ty.clone())
|
Some(ty.clone())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -145,15 +145,7 @@ pub(crate) fn expand(
|
||||||
};
|
};
|
||||||
// `mixed_site` ensures that the data is not accessible to the user-controlled code.
|
// `mixed_site` ensures that the data is not accessible to the user-controlled code.
|
||||||
let data = Ident::new("__data", Span::mixed_site());
|
let data = Ident::new("__data", Span::mixed_site());
|
||||||
let init_fields = init_fields(
|
let init_fields = init_fields(&fields, pinned, &data, &slot);
|
||||||
&fields,
|
|
||||||
pinned,
|
|
||||||
!attrs
|
|
||||||
.iter()
|
|
||||||
.any(|attr| matches!(attr, InitializerAttribute::DisableInitializedFieldAccess)),
|
|
||||||
&data,
|
|
||||||
&slot,
|
|
||||||
);
|
|
||||||
let field_check = make_field_check(&fields, init_kind, &path);
|
let field_check = make_field_check(&fields, init_kind, &path);
|
||||||
Ok(quote! {{
|
Ok(quote! {{
|
||||||
// We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
|
// 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(
|
fn init_fields(
|
||||||
fields: &Punctuated<InitializerField, Token![,]>,
|
fields: &Punctuated<InitializerField, Token![,]>,
|
||||||
pinned: bool,
|
pinned: bool,
|
||||||
generate_initialized_accessors: bool,
|
|
||||||
data: &Ident,
|
data: &Ident,
|
||||||
slot: &Ident,
|
slot: &Ident,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
|
@ -272,13 +263,6 @@ fn init_fields(
|
||||||
unsafe { &mut (*#slot).#ident }
|
unsafe { &mut (*#slot).#ident }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let accessor = generate_initialized_accessors.then(|| {
|
|
||||||
quote! {
|
|
||||||
#(#cfgs)*
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
let #ident = #accessor;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
quote! {
|
quote! {
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
{
|
{
|
||||||
|
|
@ -286,7 +270,9 @@ fn init_fields(
|
||||||
// SAFETY: TODO
|
// SAFETY: TODO
|
||||||
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
|
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
|
||||||
}
|
}
|
||||||
#accessor
|
#(#cfgs)*
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
let #ident = #accessor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InitializerKind::Init { ident, value, .. } => {
|
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! {
|
quote! {
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
{
|
{
|
||||||
let #init = #value;
|
let #init = #value;
|
||||||
#value_init
|
#value_init
|
||||||
}
|
}
|
||||||
#accessor
|
#(#cfgs)*
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
let #ident = #accessor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InitializerKind::Code { block: value, .. } => quote! {
|
InitializerKind::Code { block: value, .. } => quote! {
|
||||||
|
|
@ -466,10 +447,6 @@ impl Parse for Initializer {
|
||||||
if a.path().is_ident("default_error") {
|
if a.path().is_ident("default_error") {
|
||||||
a.parse_args::<DefaultErrorAttribute>()
|
a.parse_args::<DefaultErrorAttribute>()
|
||||||
.map(InitializerAttribute::DefaultError)
|
.map(InitializerAttribute::DefaultError)
|
||||||
} else if a.path().is_ident("disable_initialized_field_access") {
|
|
||||||
a.meta
|
|
||||||
.require_path_only()
|
|
||||||
.map(|_| InitializerAttribute::DisableInitializedFieldAccess)
|
|
||||||
} else {
|
} else {
|
||||||
Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
|
Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue