rust: init: add Zeroable
trait and init::zeroed
function
Add the `Zeroable` trait which marks types that can be initialized by writing `0x00` to every byte of the type. Also add the `init::zeroed` function that creates an initializer for a `Zeroable` type that writes `0x00` to every byte. Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Gary Guo <gary@garyguo.net> Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com> Link: https://lore.kernel.org/r/20230408122429.1103522-12-y86-dev@protonmail.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
6841d45a30
commit
38cde0bd7b
@ -195,8 +195,14 @@ use crate::{
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use core::{
|
||||
alloc::AllocError, cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit,
|
||||
pin::Pin, ptr,
|
||||
alloc::AllocError,
|
||||
cell::Cell,
|
||||
convert::Infallible,
|
||||
marker::PhantomData,
|
||||
mem::MaybeUninit,
|
||||
num::*,
|
||||
pin::Pin,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -1323,3 +1329,90 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
|
||||
/// automatically.
|
||||
fn drop(self: Pin<&mut Self>, only_call_from_drop: __internal::OnlyCallFromDrop);
|
||||
}
|
||||
|
||||
/// Marker trait for types that can be initialized by writing just zeroes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The bit pattern consisting of only zeroes is a valid bit pattern for this type. In other words,
|
||||
/// this is not UB:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let val: Self = unsafe { core::mem::zeroed() };
|
||||
/// ```
|
||||
pub unsafe trait Zeroable {}
|
||||
|
||||
/// Create a new zeroed T.
|
||||
///
|
||||
/// The returned initializer will write `0x00` to every byte of the given `slot`.
|
||||
#[inline]
|
||||
pub fn 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 {
|
||||
init_from_closure(|slot: *mut T| {
|
||||
slot.write_bytes(0, 1);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_zeroable {
|
||||
($($({$($generics:tt)*})? $t:ty, )*) => {
|
||||
$(unsafe impl$($($generics)*)? Zeroable for $t {})*
|
||||
};
|
||||
}
|
||||
|
||||
impl_zeroable! {
|
||||
// SAFETY: All primitives that are allowed to be zero.
|
||||
bool,
|
||||
char,
|
||||
u8, u16, u32, u64, u128, usize,
|
||||
i8, i16, i32, i64, i128, isize,
|
||||
f32, f64,
|
||||
|
||||
// SAFETY: These are ZSTs, there is nothing to zero.
|
||||
{<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (),
|
||||
|
||||
// SAFETY: Type is allowed to take any value, including all zeros.
|
||||
{<T>} MaybeUninit<T>,
|
||||
|
||||
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee).
|
||||
Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>,
|
||||
Option<NonZeroU128>, Option<NonZeroUsize>,
|
||||
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
|
||||
Option<NonZeroI128>, Option<NonZeroIsize>,
|
||||
|
||||
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee).
|
||||
//
|
||||
// In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant.
|
||||
{<T: ?Sized>} Option<NonNull<T>>,
|
||||
{<T: ?Sized>} Option<Box<T>>,
|
||||
|
||||
// SAFETY: `null` pointer is valid.
|
||||
//
|
||||
// We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be
|
||||
// null.
|
||||
//
|
||||
// When `Pointee` gets stabilized, we could use
|
||||
// `T: ?Sized where <T as Pointee>::Metadata: Zeroable`
|
||||
{<T>} *mut T, {<T>} *const T,
|
||||
|
||||
// SAFETY: `null` pointer is valid and the metadata part of these fat pointers is allowed to be
|
||||
// zero.
|
||||
{<T>} *mut [T], {<T>} *const [T], *mut str, *const str,
|
||||
|
||||
// SAFETY: `T` is `Zeroable`.
|
||||
{<const N: usize, T: Zeroable>} [T; N], {<T: Zeroable>} Wrapping<T>,
|
||||
}
|
||||
|
||||
macro_rules! impl_tuple_zeroable {
|
||||
($(,)?) => {};
|
||||
($first:ident, $($t:ident),* $(,)?) => {
|
||||
// SAFETY: All elements are zeroable and padding can be zero.
|
||||
unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {}
|
||||
impl_tuple_zeroable!($($t),* ,);
|
||||
}
|
||||
}
|
||||
|
||||
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);
|
||||
|
Loading…
Reference in New Issue
Block a user