Skip to content

Commit d1a77c2

Browse files
y86-devojeda
authored andcommitted
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 <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Gary Guo <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 72d01f9 commit d1a77c2

File tree

1 file changed

+95
-2
lines changed

1 file changed

+95
-2
lines changed

rust/kernel/init.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,14 @@ use crate::{
195195
};
196196
use alloc::boxed::Box;
197197
use core::{
198-
alloc::AllocError, cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit,
199-
pin::Pin, ptr,
198+
alloc::AllocError,
199+
cell::Cell,
200+
convert::Infallible,
201+
marker::PhantomData,
202+
mem::MaybeUninit,
203+
num::*,
204+
pin::Pin,
205+
ptr::{self, NonNull},
200206
};
201207

202208
#[doc(hidden)]
@@ -1323,3 +1329,90 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
13231329
/// automatically.
13241330
fn drop(self: Pin<&mut Self>, only_call_from_drop: __internal::OnlyCallFromDrop);
13251331
}
1332+
1333+
/// Marker trait for types that can be initialized by writing just zeroes.
1334+
///
1335+
/// # Safety
1336+
///
1337+
/// The bit pattern consisting of only zeroes is a valid bit pattern for this type. In other words,
1338+
/// this is not UB:
1339+
///
1340+
/// ```rust,ignore
1341+
/// let val: Self = unsafe { core::mem::zeroed() };
1342+
/// ```
1343+
pub unsafe trait Zeroable {}
1344+
1345+
/// Create a new zeroed T.
1346+
///
1347+
/// The returned initializer will write `0x00` to every byte of the given `slot`.
1348+
#[inline]
1349+
pub fn zeroed<T: Zeroable>() -> impl Init<T> {
1350+
// SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`
1351+
// and because we write all zeroes, the memory is initialized.
1352+
unsafe {
1353+
init_from_closure(|slot: *mut T| {
1354+
slot.write_bytes(0, 1);
1355+
Ok(())
1356+
})
1357+
}
1358+
}
1359+
1360+
macro_rules! impl_zeroable {
1361+
($($({$($generics:tt)*})? $t:ty, )*) => {
1362+
$(unsafe impl$($($generics)*)? Zeroable for $t {})*
1363+
};
1364+
}
1365+
1366+
impl_zeroable! {
1367+
// SAFETY: All primitives that are allowed to be zero.
1368+
bool,
1369+
char,
1370+
u8, u16, u32, u64, u128, usize,
1371+
i8, i16, i32, i64, i128, isize,
1372+
f32, f64,
1373+
1374+
// SAFETY: These are ZSTs, there is nothing to zero.
1375+
{<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (),
1376+
1377+
// SAFETY: Type is allowed to take any value, including all zeros.
1378+
{<T>} MaybeUninit<T>,
1379+
1380+
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee).
1381+
Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>,
1382+
Option<NonZeroU128>, Option<NonZeroUsize>,
1383+
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
1384+
Option<NonZeroI128>, Option<NonZeroIsize>,
1385+
1386+
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee).
1387+
//
1388+
// In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant.
1389+
{<T: ?Sized>} Option<NonNull<T>>,
1390+
{<T: ?Sized>} Option<Box<T>>,
1391+
1392+
// SAFETY: `null` pointer is valid.
1393+
//
1394+
// We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be
1395+
// null.
1396+
//
1397+
// When `Pointee` gets stabilized, we could use
1398+
// `T: ?Sized where <T as Pointee>::Metadata: Zeroable`
1399+
{<T>} *mut T, {<T>} *const T,
1400+
1401+
// SAFETY: `null` pointer is valid and the metadata part of these fat pointers is allowed to be
1402+
// zero.
1403+
{<T>} *mut [T], {<T>} *const [T], *mut str, *const str,
1404+
1405+
// SAFETY: `T` is `Zeroable`.
1406+
{<const N: usize, T: Zeroable>} [T; N], {<T: Zeroable>} Wrapping<T>,
1407+
}
1408+
1409+
macro_rules! impl_tuple_zeroable {
1410+
($(,)?) => {};
1411+
($first:ident, $($t:ident),* $(,)?) => {
1412+
// SAFETY: All elements are zeroable and padding can be zero.
1413+
unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {}
1414+
impl_tuple_zeroable!($($t),* ,);
1415+
}
1416+
}
1417+
1418+
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);

0 commit comments

Comments
 (0)