summaryrefslogtreecommitdiff
path: root/rust/pin-init/src/lib.rs
diff options
context:
space:
mode:
authorMiguel Ojeda <ojeda@kernel.org>2025-07-13 23:05:14 +0200
committerMiguel Ojeda <ojeda@kernel.org>2025-07-13 23:05:14 +0200
commite8fa0481ea15ba1d40a836fa5dbfc1f49680fba8 (patch)
treefe27d83903fb413e95ce0846aaab87bf44037cee /rust/pin-init/src/lib.rs
parent2009a2d5696944d85c34d75e691a6f3884e787c0 (diff)
parentfc3870dc5cadb701b4122e4a8daa85f9fa2f57b9 (diff)
Merge tag 'pin-init-v6.17' of https://github.com/Rust-for-Linux/linux into rust-next
Pull pin-init updates from Benno Lossin: "Added: - 'impl<T, E> [Pin]Init<T, E> for Result<T, E>', so results are now (pin-)initializers. - 'Zeroable::init_zeroed()' delegating to 'init_zeroed()'. - New 'zeroed()', a safe version of 'mem::zeroed()' and also provide it via 'Zeroable::zeroed()'. - Implement 'Zeroable' for 'Option<&T>' and 'Option<&mut T>'. - Implement 'Zeroable' for 'Option<[unsafe] [extern "abi"] fn(...args...) -> ret>' for '"Rust"' and '"C"' ABIs and up to 20 arguments. Changed: - Blanket impls of 'Init' and 'PinInit' from 'impl<T, E> [Pin]Init<T, E> for T' to 'impl<T> [Pin]Init<T> for T'. - Renamed 'zeroed()' to 'init_zeroed()'. Upstream dev news: - More CI improvements to deny warnings, use '--all-targets'. Also check the synchronization status of the two '-next' branches in upstream and the kernel." Acked-by: Andreas Hindborg <a.hindborg@kernel.org> * tag 'pin-init-v6.17' of https://github.com/Rust-for-Linux/linux: rust: pin-init: examples, tests: use `ignore` instead of conditionally compiling tests rust: init: remove doctest's `Error::from_errno` workaround rust: init: re-enable doctests rust: pin-init: implement `ZeroableOption` for function pointers with up to 20 arguments rust: pin-init: change `impl Zeroable for Option<NonNull<T>>` to `ZeroableOption for NonNull<T>` rust: pin-init: implement `ZeroableOption` for `&T` and `&mut T` rust: pin-init: add `zeroed()` & `Zeroable::zeroed()` functions rust: pin-init: add `Zeroable::init_zeroed` rust: pin-init: rename `zeroed` to `init_zeroed` rust: pin-init: feature-gate the `stack_init_reuse` test on the `std` feature rust: pin-init: examples: pthread_mutex: disable the main test for miri rust: pin-init: examples, tests: add conditional compilation in order to compile under any feature combination rust: pin-init: change blanket impls for `[Pin]Init` and add one for `Result<T, E>` rust: pin-init: improve safety documentation for `impl<T> [Pin]Init<T> for T`
Diffstat (limited to 'rust/pin-init/src/lib.rs')
-rw-r--r--rust/pin-init/src/lib.rs158
1 files changed, 135 insertions, 23 deletions
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index c5f395b44ec8..62e013a5cc20 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -148,7 +148,7 @@
//! fn new() -> impl PinInit<Self, Error> {
//! try_pin_init!(Self {
//! status <- CMutex::new(0),
-//! buffer: Box::init(pin_init::zeroed())?,
+//! buffer: Box::init(pin_init::init_zeroed())?,
//! }? Error)
//! }
//! }
@@ -742,7 +742,7 @@ macro_rules! stack_try_pin_init {
/// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
/// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
/// pointer named `this` inside of the initializer.
-/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the
+/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the
/// struct, this initializes every field with 0 and then runs all initializers specified in the
/// body. This can only be done if [`Zeroable`] is implemented for the struct.
///
@@ -769,7 +769,7 @@ macro_rules! stack_try_pin_init {
/// });
/// let init = pin_init!(Buf {
/// buf: [1; 64],
-/// ..Zeroable::zeroed()
+/// ..Zeroable::init_zeroed()
/// });
/// ```
///
@@ -805,7 +805,7 @@ macro_rules! pin_init {
/// ```rust
/// # #![feature(allocator_api)]
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
-/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed};
+/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};
///
/// #[pin_data]
/// struct BigBuf {
@@ -817,7 +817,7 @@ macro_rules! pin_init {
/// impl BigBuf {
/// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self {
-/// big: Box::init(zeroed())?,
+/// big: Box::init(init_zeroed())?,
/// small: [0; 1024 * 1024],
/// ptr: core::ptr::null_mut(),
/// }? Error)
@@ -866,7 +866,7 @@ macro_rules! try_pin_init {
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use pin_init::InPlaceInit;
-/// use pin_init::{init, Init, zeroed};
+/// use pin_init::{init, Init, init_zeroed};
///
/// struct BigBuf {
/// small: [u8; 1024 * 1024],
@@ -875,7 +875,7 @@ macro_rules! try_pin_init {
/// impl BigBuf {
/// fn new() -> impl Init<Self> {
/// init!(Self {
-/// small <- zeroed(),
+/// small <- init_zeroed(),
/// })
/// }
/// }
@@ -913,7 +913,7 @@ macro_rules! init {
/// # #![feature(allocator_api)]
/// # use core::alloc::AllocError;
/// # use pin_init::InPlaceInit;
-/// use pin_init::{try_init, Init, zeroed};
+/// use pin_init::{try_init, Init, init_zeroed};
///
/// struct BigBuf {
/// big: Box<[u8; 1024 * 1024 * 1024]>,
@@ -923,7 +923,7 @@ macro_rules! init {
/// impl BigBuf {
/// fn new() -> impl Init<Self, AllocError> {
/// try_init!(Self {
-/// big: Box::init(zeroed())?,
+/// big: Box::init(init_zeroed())?,
/// small: [0; 1024 * 1024],
/// }? AllocError)
/// }
@@ -1170,7 +1170,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
///
/// ```rust
/// # #![expect(clippy::disallowed_names)]
- /// use pin_init::{init, zeroed, Init};
+ /// use pin_init::{init, init_zeroed, Init};
///
/// struct Foo {
/// buf: [u8; 1_000_000],
@@ -1183,7 +1183,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// }
///
/// let foo = init!(Foo {
- /// buf <- zeroed()
+ /// buf <- init_zeroed()
/// }).chain(|foo| {
/// foo.setup();
/// Ok(())
@@ -1390,20 +1390,44 @@ where
unsafe { pin_init_from_closure(init) }
}
-// SAFETY: Every type can be initialized by-value.
-unsafe impl<T, E> Init<T, E> for T {
- unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
- // SAFETY: TODO.
+// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`.
+unsafe impl<T> Init<T> for T {
+ unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {
+ // SAFETY: `slot` is valid for writes by the safety requirements of this function.
unsafe { slot.write(self) };
Ok(())
}
}
-// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`.
-unsafe impl<T, E> PinInit<T, E> for T {
+// SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of
+// `slot`. Additionally, all pinning invariants of `T` are upheld.
+unsafe impl<T> PinInit<T> for T {
+ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> {
+ // SAFETY: `slot` is valid for writes by the safety requirements of this function.
+ unsafe { slot.write(self) };
+ Ok(())
+ }
+}
+
+// SAFETY: when the `__init` function returns with
+// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld.
+// - `Err(err)`, slot was not written to.
+unsafe impl<T, E> Init<T, E> for Result<T, E> {
+ unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
+ // SAFETY: `slot` is valid for writes by the safety requirements of this function.
+ unsafe { slot.write(self?) };
+ Ok(())
+ }
+}
+
+// SAFETY: when the `__pinned_init` function returns with
+// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld.
+// - `Err(err)`, slot was not written to.
+unsafe impl<T, E> PinInit<T, E> for Result<T, E> {
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
- // SAFETY: TODO.
- unsafe { self.__init(slot) }
+ // SAFETY: `slot` is valid for writes by the safety requirements of this function.
+ unsafe { slot.write(self?) };
+ Ok(())
}
}
@@ -1471,7 +1495,45 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
/// ```rust,ignore
/// let val: Self = unsafe { core::mem::zeroed() };
/// ```
-pub unsafe trait Zeroable {}
+pub unsafe trait Zeroable {
+ /// Create a new zeroed `Self`.
+ ///
+ /// The returned initializer will write `0x00` to every byte of the given `slot`.
+ #[inline]
+ fn init_zeroed() -> impl Init<Self>
+ where
+ Self: Sized,
+ {
+ init_zeroed()
+ }
+
+ /// Create a `Self` consisting of all zeroes.
+ ///
+ /// Whenever a type implements [`Zeroable`], this function should be preferred over
+ /// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use pin_init::{Zeroable, zeroed};
+ ///
+ /// #[derive(Zeroable)]
+ /// struct Point {
+ /// x: u32,
+ /// y: u32,
+ /// }
+ ///
+ /// let point: Point = zeroed();
+ /// assert_eq!(point.x, 0);
+ /// assert_eq!(point.y, 0);
+ /// ```
+ fn zeroed() -> Self
+ where
+ Self: Sized,
+ {
+ zeroed()
+ }
+}
/// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write
/// `None` to that location.
@@ -1484,11 +1546,21 @@ pub unsafe trait ZeroableOption {}
// SAFETY: by the safety requirement of `ZeroableOption`, this is valid.
unsafe impl<T: ZeroableOption> Zeroable for Option<T> {}
-/// Create a new zeroed T.
+// SAFETY: `Option<&T>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for &T {}
+// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for &mut T {}
+// SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for NonNull<T> {}
+
+/// Create an initializer for a zeroed `T`.
///
/// The returned initializer will write `0x00` to every byte of the given `slot`.
#[inline]
-pub fn zeroed<T: Zeroable>() -> impl Init<T> {
+pub fn init_zeroed<T: Zeroable>() -> impl Init<T> {
// SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`
// and because we write all zeroes, the memory is initialized.
unsafe {
@@ -1499,6 +1571,31 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {
}
}
+/// Create a `T` consisting of all zeroes.
+///
+/// Whenever a type implements [`Zeroable`], this function should be preferred over
+/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
+///
+/// # Examples
+///
+/// ```
+/// use pin_init::{Zeroable, zeroed};
+///
+/// #[derive(Zeroable)]
+/// struct Point {
+/// x: u32,
+/// y: u32,
+/// }
+///
+/// let point: Point = zeroed();
+/// assert_eq!(point.x, 0);
+/// assert_eq!(point.y, 0);
+/// ```
+pub const fn zeroed<T: Zeroable>() -> T {
+ // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`.
+ unsafe { core::mem::zeroed() }
+}
+
macro_rules! impl_zeroable {
($($({$($generics:tt)*})? $t:ty, )*) => {
// SAFETY: Safety comments written in the macro invocation.
@@ -1536,7 +1633,6 @@ impl_zeroable! {
Option<NonZeroU128>, Option<NonZeroUsize>,
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
Option<NonZeroI128>, Option<NonZeroIsize>,
- {<T>} Option<NonNull<T>>,
// SAFETY: `null` pointer is valid.
//
@@ -1566,6 +1662,22 @@ macro_rules! impl_tuple_zeroable {
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);
+macro_rules! impl_fn_zeroable_option {
+ ([$($abi:literal),* $(,)?] $args:tt) => {
+ $(impl_fn_zeroable_option!({extern $abi} $args);)*
+ $(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
+ };
+ ({$($prefix:tt)*} {$(,)?}) => {};
+ ({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
+ // SAFETY: function pointers are part of the option layout optimization:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+ unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
+ impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,});
+ };
+}
+
+impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
+
/// 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).
///