From 050885840917497c90f046ff8763d172b4c3ba4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Wed, 24 Jan 2024 16:48:24 +0300 Subject: [PATCH] Add `FromBytes::getrandom` method gated --- Cargo.toml | 1 + src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 516c387b64..4770801a59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd"] [dependencies] zerocopy-derive = { version = "=0.8.0-alpha.2", path = "zerocopy-derive", optional = true } +getrandom = { version = "0.2", optional = true } # The "associated proc macro pattern" ensures that the versions of zerocopy and # zerocopy-derive remain equal, even if the 'derive' feature isn't used. diff --git a/src/lib.rs b/src/lib.rs index f4fb1de894..3600cc5a06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2464,6 +2464,40 @@ pub unsafe trait FromBytes: FromZeros { Ref::<_, Unalign>::new_unaligned_from_suffix(bytes) .map(|(_, r)| r.read().into_inner()) } + + /// Generate random value of `Self` using OS randomness source + /// (see the table in the [`getrandom`] crate docs for more information). + /// + /// # Examples + /// ``` + /// # fn main() -> Result<(), getrandom::Error> { + /// use zerocopy::FromBytes; + /// + /// let seed = u32::getrandom()?; + /// let key: [u8; 16] = FromBytes::getrandom()?; + /// # Ok(()) } + /// ``` + #[cfg(feature = "getrandom")] + #[inline] + fn getrandom() -> Result + where + Self: Sized, + { + let mut value = MaybeUninit::::uninit(); + // SAFETY: it's safe to cast `&mut MaybeUninit` to `&mut [MaybeUninit]` + // with slice length equal to `size_of::()`. The compiler will ensure that + // `T` isn't too large. + unsafe { + let ptr: *mut MaybeUninit = value.as_mut_ptr().cast(); + let size = core::mem::size_of::(); + let uninit_bytes = core::slice::from_raw_parts_mut(ptr, size); + getrandom::getrandom_uninit(uninit_bytes)?; + }; + // SAFETY: when `getrandom_uninit` returns `Ok` all bytes in `uninit_bytes` + // (and thus in `value`) are properly initialized. Any bit-sequence is valid + // for `T: FromBytes`, so we can safely execute `assume_init` on `value`. + Ok(unsafe { value.assume_init() }) + } } /// Analyzes whether a type is [`IntoBytes`].