From 90348980a305cc24a067cc6e606e1c318e277930 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 21 Apr 2025 22:17:50 +0000 Subject: rust: pin-init: add `cast_[pin_]init` functions to change the initialized type These functions cast the given pointer from one type to another. They are particularly useful when initializing transparent wrapper types. Link: https://github.com/Rust-for-Linux/pin-init/pull/39/commits/80c03ddee41b154f1099fd8cc7c2bbd8c80af0ad Reviewed-by: Christian Schrefl Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 0806c689f693..a880c21d3f09 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1216,6 +1216,38 @@ pub const unsafe fn init_from_closure( __internal::InitClosure(f, PhantomData) } +/// Changes the to be initialized type. +/// +/// # Safety +/// +/// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a +/// pointer must result in a valid `U`. +#[expect(clippy::let_and_return)] +pub const unsafe fn cast_pin_init(init: impl PinInit) -> impl PinInit { + // SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety + // requirements. + let res = unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::())) }; + // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a + // cycle when computing the type returned by this function) + res +} + +/// Changes the to be initialized type. +/// +/// # Safety +/// +/// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a +/// pointer must result in a valid `U`. +#[expect(clippy::let_and_return)] +pub const unsafe fn cast_init(init: impl Init) -> impl Init { + // SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety + // requirements. + let res = unsafe { init_from_closure(|ptr: *mut U| init.__init(ptr.cast::())) }; + // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a + // cycle when computing the type returned by this function) + res +} + /// An initializer that leaves the memory uninitialized. /// /// The initializer is a no-op. The `slot` memory is not changed. -- cgit v1.2.3 From 2f7c73825f8f435ebdfb2cfa3b01cfa2b1c79041 Mon Sep 17 00:00:00 2001 From: Christian Schrefl Date: Mon, 21 Apr 2025 22:17:59 +0000 Subject: rust: pin-init: Add the `Wrapper` trait. This trait allows creating `PinInitializers` for wrapper or new-type structs with the inner value structurally pinned, when given the initializer for the inner value. Implement this trait for `UnsafeCell` and `MaybeUninit`. Signed-off-by: Christian Schrefl Link: https://github.com/Rust-for-Linux/pin-init/pull/37/commits/3ab4db083bd7b41a1bc23d937224f975d7400e50 [ Reworded commit message into imperative mode, fixed typo and fixed commit authorship. - Benno ] Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index a880c21d3f09..467ccc8bd616 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1513,3 +1513,47 @@ macro_rules! impl_tuple_zeroable { } impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); + +/// This trait allows creating an instance of `Self` which contains exactly one +/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning). +/// +/// This is useful when using wrapper `struct`s like [`UnsafeCell`] or with new-type `struct`s. +/// +/// # Examples +/// +/// ``` +/// # use core::cell::UnsafeCell; +/// # use pin_init::{pin_data, pin_init, Wrapper}; +/// +/// #[pin_data] +/// struct Foo {} +/// +/// #[pin_data] +/// struct Bar { +/// #[pin] +/// content: UnsafeCell +/// }; +/// +/// let foo_initializer = pin_init!(Foo{}); +/// let initializer = pin_init!(Bar { +/// content <- UnsafeCell::pin_init(foo_initializer) +/// }); +/// ``` +pub trait Wrapper { + /// Create an pin-initializer for a [`Self`] containing `T` form the `value_init` initializer. + fn pin_init(value_init: impl PinInit) -> impl PinInit; +} + +impl Wrapper for UnsafeCell { + fn pin_init(value_init: impl PinInit) -> impl PinInit { + // SAFETY: `UnsafeCell` has a compatible layout to `T`. + unsafe { cast_pin_init(value_init) } + } +} + +impl Wrapper for MaybeUninit { + fn pin_init(value_init: impl PinInit) -> impl PinInit { + // SAFETY: `MaybeUninit` has a compatible layout to `T`. + unsafe { cast_pin_init(value_init) } + } +} -- cgit v1.2.3 From b862aac8fd46601fa20226c9f5d6c6d308678b4d Mon Sep 17 00:00:00 2001 From: Christian Schrefl Date: Mon, 21 Apr 2025 22:18:06 +0000 Subject: rust: pin-init: Implement `Wrapper` for `UnsafePinned` behind feature flag. Add the `unsafe-pinned` feature which gates the `Wrapper` implementation of the `core::pin::UnsafePinned` struct. For now this is just a cargo feature, but once `core::pin::UnsafePinned` is stable a config flag can be added to allow the usage of this implementation in the linux kernel. Signed-off-by: Christian Schrefl Link: https://github.com/Rust-for-Linux/pin-init/pull/37/commits/99cb1934425357e780ea5b0628f66633123847b8 [ Fixed commit authorship. - Benno ] Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 467ccc8bd616..745cf534d239 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -269,6 +269,10 @@ #![forbid(missing_docs, unsafe_op_in_unsafe_fn)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "alloc", feature(allocator_api))] +#![cfg_attr( + all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED), + feature(unsafe_pinned) +)] use core::{ cell::UnsafeCell, @@ -1557,3 +1561,11 @@ impl Wrapper for MaybeUninit { unsafe { cast_pin_init(value_init) } } } + +#[cfg(all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED))] +impl Wrapper for core::pin::UnsafePinned { + fn pin_init(init: impl PinInit) -> impl PinInit { + // SAFETY: `UnsafePinned` has a compatible layout to `T`. + unsafe { cast_pin_init(init) } + } +} -- cgit v1.2.3 From bc5f3e0e01a5f2d067ff4292d5a10093ae680f53 Mon Sep 17 00:00:00 2001 From: Christian Schrefl Date: Mon, 21 Apr 2025 22:18:13 +0000 Subject: rust: pin-init: Update Changelog and Readme Add Changelog entry for the `Wrapper` trait and document the `unsafe-pinned` feature in the Readme. Signed-off-by: Christian Schrefl Link: https://github.com/Rust-for-Linux/pin-init/pull/37/commits/986555f564645efb238e8092c6314388c859efe5 [ Fixed commit authorship. - Benno ] Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 745cf534d239..1521500a46b1 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -32,6 +32,12 @@ //! will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std //! mode. //! +//! ## Nightly needed for `unsafe-pinned` feature +//! +//! This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type. +//! This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735) +//! and therefore a nightly compiler. Note that this feature is not enabled by default. +//! //! # Overview //! //! To initialize a `struct` with an in-place constructor you will need two things: -- cgit v1.2.3 From c3815aa4bb5c6248e78785269357e87bfa4d0909 Mon Sep 17 00:00:00 2001 From: Christian Schrefl Date: Mon, 21 Apr 2025 22:18:23 +0000 Subject: rust: pin-init: Update the structural pinning link in readme. The previous link anchor was broken in rust 1.77, because the documentation was refactored in upstream rust. Change the link to refer to the new section in the rust documentation. Signed-off-by: Christian Schrefl Link: https://github.com/Rust-for-Linux/pin-init/pull/37/commits/a146142fe18cafa52f8c6da306ca2729d789cfbf [ Fixed commit authorship. - Benno ] Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 1521500a46b1..774f8ca033bc 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -247,7 +247,7 @@ //! [`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html //! [pinning]: https://doc.rust-lang.org/std/pin/index.html //! [structurally pinned fields]: -//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field +//! https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning //! [stack]: crate::stack_pin_init #![cfg_attr( kernel, -- cgit v1.2.3 From 983d13fc2cf12f0a753700d48be7d04155a1272c Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 21 Apr 2025 22:18:33 +0000 Subject: rust: pin-init: allow `pub` fields in `derive(Zeroable)` Add support for parsing `pub`, `pub(crate)` and `pub(super)` to the derive macro `Zeroable`. Link: https://github.com/Rust-for-Linux/pin-init/pull/42/commits/e8311e52ca57273e7ed6d099144384971677a0ba Signed-off-by: Benno Lossin --- rust/pin-init/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index 361623324d5c..e4054fe3ed3d 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -1393,7 +1393,7 @@ macro_rules! __derive_zeroable { @body({ $( $(#[$($field_attr:tt)*])* - $field:ident : $field_ty:ty + $field_vis:vis $field:ident : $field_ty:ty ),* $(,)? }), ) => { -- cgit v1.2.3 From a313d41a2b515bbb76d56df490b731ff6d64e571 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 21 Apr 2025 22:18:41 +0000 Subject: rust: pin-init: allow `Zeroable` derive macro to also be applied to unions Enabling the same behavior for unions as for structs is correct, but could be relaxed: the valid bit patterns for unions are the union of all valid bit patterns of their fields. So for a union to implement `Zeroable`, only a single field needs to implement `Zeroable`. This can be a future improvement, as it is currently only needed for unions where all fields implement `Zeroable`. There is no danger for mis-parsing with the two optional tokens (ie neither one or both tokens are parsed), as the compiler will already have rejected that before giving it as the input to the derive macro. Link: https://github.com/Rust-for-Linux/pin-init/pull/42/commits/5927b497ce522d82f6c082d5ba9235df57bfdb32 Signed-off-by: Benno Lossin --- rust/pin-init/src/macros.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index e4054fe3ed3d..332d7e08925b 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -1412,4 +1412,34 @@ macro_rules! __derive_zeroable { } }; }; + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis union $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field_vis:vis $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*> + where + $($($whr)*)? + {} + const _: () = { + fn assert_zeroable() {} + fn ensure_zeroable<$($impl_generics)*>() + where $($($whr)*)? + { + $(assert_zeroable::<$field_ty>();)* + } + }; + }; } -- cgit v1.2.3 From 00fccd3ecc2129ee32fd181079eb643f497044c4 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 21 Apr 2025 22:18:52 +0000 Subject: rust: pin-init: add `MaybeZeroable` derive macro This derive macro implements `Zeroable` for structs & unions precisely if all fields also implement `Zeroable` and does nothing otherwise. The plain `Zeroable` derive macro instead errors when it cannot derive `Zeroable` safely. The `MaybeZeroable` derive macro is useful in cases where manual checking is infeasible such as with the bindings crate. Move the zeroable generics parsing into a standalone function in order to avoid code duplication between the two derive macros. Link: https://github.com/Rust-for-Linux/pin-init/pull/42/commits/1165cdad1a391b923efaf30cf76bc61e38da022e Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 30 +++++++++++++++++++++++ rust/pin-init/src/macros.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 774f8ca033bc..05a0cd6ad8f4 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -413,6 +413,36 @@ pub use ::pin_init_internal::pinned_drop; /// ``` pub use ::pin_init_internal::Zeroable; +/// Derives the [`Zeroable`] trait for the given struct if all fields implement [`Zeroable`]. +/// +/// Contrary to the derive macro named [`macro@Zeroable`], this one silently fails when a field +/// doesn't implement [`Zeroable`]. +/// +/// # Examples +/// +/// ``` +/// use pin_init::MaybeZeroable; +/// +/// // implmements `Zeroable` +/// #[derive(MaybeZeroable)] +/// pub struct DriverData { +/// id: i64, +/// buf_ptr: *mut u8, +/// len: usize, +/// } +/// +/// // does not implmement `Zeroable` +/// #[derive(MaybeZeroable)] +/// pub struct DriverData2 { +/// id: i64, +/// buf_ptr: *mut u8, +/// len: usize, +/// // this field doesn't implement `Zeroable` +/// other_data: &'static i32, +/// } +/// ``` +pub use ::pin_init_internal::MaybeZeroable; + /// Initialize and pin a type directly on the stack. /// /// # Examples diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index 332d7e08925b..935d77745d1d 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -1443,3 +1443,62 @@ macro_rules! __derive_zeroable { }; }; } + +#[doc(hidden)] +#[macro_export] +macro_rules! __maybe_derive_zeroable { + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field_vis:vis $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*> + where + $( + // the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds` + // feature . + $field_ty: for<'__dummy> $crate::Zeroable, + )* + $($($whr)*)? + {} + }; + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis union $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field_vis:vis $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*> + where + $( + // the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds` + // feature . + $field_ty: for<'__dummy> $crate::Zeroable, + )* + $($($whr)*)? + {} + }; +} -- cgit v1.2.3 From a919ba21594bfa1e67639785d409e1bdce332097 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Sat, 26 Apr 2025 08:39:22 +0000 Subject: rust: pin-init: fix typos Correct two typos in the `Wrapper::pin_init` documentation. Link: https://github.com/Rust-for-Linux/pin-init/pull/48/commits/fd0bf5e244b685188dc642fc4a0bd3f042468fdb Reviewed-by: Christian Schrefl Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 05a0cd6ad8f4..b5a295effd9c 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1580,7 +1580,7 @@ impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); /// }); /// ``` pub trait Wrapper { - /// Create an pin-initializer for a [`Self`] containing `T` form the `value_init` initializer. + /// Creates an pin-initializer for a [`Self`] containing `T` from the `value_init` initializer. fn pin_init(value_init: impl PinInit) -> impl PinInit; } -- cgit v1.2.3 From 9de1a293c8ece00d226b21a35751ec178be2a9fa Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Sat, 26 Apr 2025 08:39:28 +0000 Subject: rust: pin-init: improve documentation for `Zeroable` derive macros Specify that both `MaybeZeroable` and `Zeroable` work on `union`s. Add a doc example for a union. Also include an example with visibility on the field. Link: https://github.com/Rust-for-Linux/pin-init/pull/48/commits/ab0985a0e08df06c60a32ca5888f74adcc2c1cf3 Reviewed-by: Christian Schrefl Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'rust/pin-init/src') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index b5a295effd9c..9ab34036e6bc 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -395,9 +395,10 @@ pub use ::pin_init_internal::pin_data; /// ``` pub use ::pin_init_internal::pinned_drop; -/// Derives the [`Zeroable`] trait for the given struct. +/// Derives the [`Zeroable`] trait for the given `struct` or `union`. /// -/// This can only be used for structs where every field implements the [`Zeroable`] trait. +/// This can only be used for `struct`s/`union`s where every field implements the [`Zeroable`] +/// trait. /// /// # Examples /// @@ -406,14 +407,25 @@ pub use ::pin_init_internal::pinned_drop; /// /// #[derive(Zeroable)] /// pub struct DriverData { -/// id: i64, +/// pub(crate) id: i64, /// buf_ptr: *mut u8, /// len: usize, /// } /// ``` +/// +/// ``` +/// use pin_init::Zeroable; +/// +/// #[derive(Zeroable)] +/// pub union SignCast { +/// signed: i64, +/// unsigned: u64, +/// } +/// ``` pub use ::pin_init_internal::Zeroable; -/// Derives the [`Zeroable`] trait for the given struct if all fields implement [`Zeroable`]. +/// Derives the [`Zeroable`] trait for the given `struct` or `union` if all fields implement +/// [`Zeroable`]. /// /// Contrary to the derive macro named [`macro@Zeroable`], this one silently fails when a field /// doesn't implement [`Zeroable`]. @@ -426,7 +438,7 @@ pub use ::pin_init_internal::Zeroable; /// // implmements `Zeroable` /// #[derive(MaybeZeroable)] /// pub struct DriverData { -/// id: i64, +/// pub(crate) id: i64, /// buf_ptr: *mut u8, /// len: usize, /// } @@ -434,7 +446,7 @@ pub use ::pin_init_internal::Zeroable; /// // does not implmement `Zeroable` /// #[derive(MaybeZeroable)] /// pub struct DriverData2 { -/// id: i64, +/// pub(crate) id: i64, /// buf_ptr: *mut u8, /// len: usize, /// // this field doesn't implement `Zeroable` -- cgit v1.2.3