diff --git a/Cargo.toml b/Cargo.toml index cfcf5575..880d56df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,9 @@ rustc-dep-of-std = [ # Unstable/test-only feature to run wasm-bindgen tests in a browser test-in-browser = [] +# Nightly-only implementation with `std::io::ReadBuf` struct. +rdbuf-impl = [] + [package.metadata.docs.rs] features = ["std", "custom"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/src/3ds.rs b/src/3ds.rs index 60305127..505c74b3 100644 --- a/src/3ds.rs +++ b/src/3ds.rs @@ -7,10 +7,12 @@ // except according to those terms. //! Implementation for Nintendo 3DS +use core::mem::MaybeUninit; + use crate::util_libc::sys_fill_exact; use crate::Error; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) }) diff --git a/src/bsd_arandom.rs b/src/bsd_arandom.rs index d4412125..eb522c2b 100644 --- a/src/bsd_arandom.rs +++ b/src/bsd_arandom.rs @@ -7,10 +7,13 @@ // except according to those terms. //! Implementation for FreeBSD and NetBSD -use crate::{util_libc::sys_fill_exact, Error}; +use core::mem::MaybeUninit; use core::ptr; -fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t { +use crate::util_libc::sys_fill_exact; +use crate::Error; + +fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; let mut len = buf.len(); let ret = unsafe { @@ -30,7 +33,7 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t { } } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // getrandom(2) was introduced in FreeBSD 12.0 and NetBSD 10.0 #[cfg(target_os = "freebsd")] { @@ -41,7 +44,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if let Some(fptr) = GETRANDOM.ptr() { let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; - return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) }); + return sys_fill_exact(dest, |buf| unsafe { + func(buf.as_mut_ptr() as *mut MaybeUninit, buf.len(), 0) + }); } } // Both FreeBSD and NetBSD will only return up to 256 bytes at a time, and diff --git a/src/dragonfly.rs b/src/dragonfly.rs index 8daaa404..f9d0c00e 100644 --- a/src/dragonfly.rs +++ b/src/dragonfly.rs @@ -7,13 +7,13 @@ // except according to those terms. //! Implementation for DragonFly BSD -use crate::{ - use_file, - util_libc::{sys_fill_exact, Weak}, - Error, -}; +use core::mem::MaybeUninit; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +use crate::use_file; +use crate::util_libc::{sys_fill_exact, Weak}; +use crate::Error; + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; diff --git a/src/espidf.rs b/src/espidf.rs index dce8a2aa..5b9d3339 100644 --- a/src/espidf.rs +++ b/src/espidf.rs @@ -7,14 +7,16 @@ // except according to those terms. //! Implementation for ESP-IDF -use crate::Error; use core::ffi::c_void; +use core::mem::MaybeUninit; + +use crate::Error; extern "C" { fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Not that NOT enabling WiFi, BT, or the voltage noise entropy source (via `bootloader_random_enable`) // will cause ESP-IDF to return pseudo-random numbers based on the voltage noise entropy, after the initial boot process: // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 572ff534..105c83ef 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -14,7 +14,7 @@ extern "C" { fn zx_cprng_draw(buffer: *mut u8, length: usize); } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - unsafe { zx_cprng_draw(dest.as_mut_ptr(), dest.len()) } +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + unsafe { zx_cprng_draw(dest.as_mut_ptr() as *mut _, dest.len()) } Ok(()) } diff --git a/src/ios.rs b/src/ios.rs index 226de16b..31109bf7 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -15,9 +15,9 @@ extern "C" { fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32; } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Apple's documentation guarantees kSecRandomDefault is a synonym for NULL. - let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr()) }; + let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr() as *mut u8) }; // errSecSuccess (from SecBase.h) is always zero. if ret != 0 { Err(Error::IOS_SEC_RANDOM) diff --git a/src/js.rs b/src/js.rs index e910f2bc..1b1b27ce 100644 --- a/src/js.rs +++ b/src/js.rs @@ -5,6 +5,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::mem::MaybeUninit; +use core::ptr; + use crate::Error; extern crate std; @@ -27,7 +30,7 @@ thread_local!( static RNG_SOURCE: Result = getrandom_init(); ); -pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { RNG_SOURCE.with(|result| { let source = result.as_ref().map_err(|&e| e)?; @@ -48,7 +51,17 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if crypto.get_random_values(&sub_buf).is_err() { return Err(Error::WEB_GET_RANDOM_VALUES); } - sub_buf.copy_to(chunk); + // SAFETY: Safe because MaybeUninit have same alignment and size as wrapped type + // and exclusive slices are always valid. + // Switch to https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write_slice + // when min supported Rust would have this. + unsafe { + ptr::copy_nonoverlapping( + chunk.as_ptr(), + chunk.as_mut_ptr() as *mut u8, + chunk.len(), + ); + } } } }; @@ -115,7 +128,7 @@ extern "C" { fn require(this: &NodeModule, s: &str) -> Result; type NodeCrypto; #[wasm_bindgen(method, js_name = randomFillSync, catch)] - fn random_fill_sync(this: &NodeCrypto, buf: &mut [u8]) -> Result<(), JsValue>; + fn random_fill_sync(this: &NodeCrypto, buf: &mut [MaybeUninit]) -> Result<(), JsValue>; // Node JS process Object (https://nodejs.org/api/process.html) #[wasm_bindgen(method, getter)] diff --git a/src/lib.rs b/src/lib.rs index c62056e5..c16d10f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,6 +155,8 @@ #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] +use core::mem::MaybeUninit; + #[macro_use] extern crate cfg_if; @@ -259,5 +261,41 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { if dest.is_empty() { return Ok(()); } - imp::getrandom_inner(dest) + imp::getrandom_inner( + // SAFETY: `MaybeUninit` have same size and alignment as wrapped value + // and it is safe to convert init value to MaybeUninit. + // See https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#layout + unsafe { + core::slice::from_raw_parts_mut(dest.as_mut_ptr() as *mut MaybeUninit, dest.len()) + }, + ) +} + +/// This version uses rdbuf-impl +/// It is intended to replace function that accepts `&mut [u8]` +/// once MSRV is bumped so you may want to use this to make easier switch +/// +/// Caller must clear dest before use because function only append data to buffer +/// until fill it to capacity. +/// +/// Blocking is possible, at least during early boot; see module documentation. +/// +/// In general, `getrandom` will be fast enough for interactive usage, though +/// significantly slower than a user-space CSPRNG; for the latter consider +/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). +#[cfg(any(doc, feature = "rdbuf-impl"))] +pub fn getrandom_buf(dest: &mut std::io::ReadBuf) -> Result<(), Error> { + if dest.capacity() == dest.filled_len() { + // Already filled + return Ok(()); + } + // SAFETY: + // 1. getrandom_inner must fill all bytes provided if succeedes. + // 2. getrandom_inner must not read from provided buffer because it can be uninit. + unsafe { + imp::getrandom_inner(dest.unfilled_mut())?; + dest.assume_init(dest.capacity()); + dest.set_filled(dest.capacity()); + } + Ok(()) } diff --git a/src/linux_android.rs b/src/linux_android.rs index 4270b67c..184dcaad 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -7,13 +7,15 @@ // except according to those terms. //! Implementation for Linux / Android +use core::mem::MaybeUninit; + use crate::{ util::LazyBool, util_libc::{last_os_error, sys_fill_exact}, {use_file, Error}, }; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // getrandom(2) was introduced in Linux 3.17 static HAS_GETRANDOM: LazyBool = LazyBool::new(); if HAS_GETRANDOM.unsync_init(is_getrandom_available) { diff --git a/src/macos.rs b/src/macos.rs index 671a053b..02e73d02 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -7,22 +7,23 @@ // except according to those terms. //! Implementation for macOS +use core::mem::{transmute, MaybeUninit}; + use crate::{ use_file, util_libc::{last_os_error, Weak}, Error, }; -use core::mem; type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // getentropy(2) was added in 10.12, Rust supports 10.7+ static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") }; if let Some(fptr) = GETENTROPY.ptr() { - let func: GetEntropyFn = unsafe { mem::transmute(fptr) }; + let func: GetEntropyFn = unsafe { transmute(fptr) }; for chunk in dest.chunks_mut(256) { - let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) }; + let ret = unsafe { func(chunk.as_mut_ptr() as *mut u8, chunk.len()) }; if ret != 0 { return Err(last_os_error()); } diff --git a/src/openbsd.rs b/src/openbsd.rs index 41371736..5d4df50b 100644 --- a/src/openbsd.rs +++ b/src/openbsd.rs @@ -9,7 +9,7 @@ //! Implementation for OpenBSD use crate::{util_libc::last_os_error, Error}; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // getentropy(2) was added in OpenBSD 5.6, so we can use it unconditionally. for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; diff --git a/src/rdrand.rs b/src/rdrand.rs index 1df21e5d..bbbcbbaf 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -69,7 +69,7 @@ fn is_rdrand_supported() -> bool { HAS_RDRAND.unsync_init(|| unsafe { (arch::__cpuid(1).ecx & FLAG) != 0 }) } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [mem::MaybeUninit]) -> Result<(), Error> { if !is_rdrand_supported() { return Err(Error::NO_RDRAND); } @@ -80,18 +80,24 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { } #[target_feature(enable = "rdrand")] -unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> { +unsafe fn rdrand_exact(dest: &mut [mem::MaybeUninit]) -> Result<(), Error> { // We use chunks_exact_mut instead of chunks_mut as it allows almost all // calls to memcpy to be elided by the compiler. let mut chunks = dest.chunks_exact_mut(WORD_SIZE); for chunk in chunks.by_ref() { - chunk.copy_from_slice(&rdrand()?); + let data = rdrand()?; + // SAFETY: MaybeUninit has same alignment and size as wrapped type. + // Switch to https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write_slice + // when it would be supported by minimal Rust version. + core::ptr::copy_nonoverlapping(data.as_ptr(), chunk.as_mut_ptr() as *mut u8, data.len()); } let tail = chunks.into_remainder(); let n = tail.len(); if n > 0 { - tail.copy_from_slice(&rdrand()?[..n]); + let data = rdrand()?; + // SAFETY: same as above + core::ptr::copy_nonoverlapping(data.as_ptr(), tail.as_mut_ptr() as *mut u8, n); } Ok(()) } diff --git a/src/solaris_illumos.rs b/src/solaris_illumos.rs index cf3067d6..2fa51700 100644 --- a/src/solaris_illumos.rs +++ b/src/solaris_illumos.rs @@ -17,19 +17,20 @@ //! To make sure we can compile on both Solaris and its derivatives, as well as //! function, we check for the existence of getrandom(2) in libc by calling //! libc::dlsym. +use core::mem; + use crate::{ use_file, util_libc::{sys_fill_exact, Weak}, Error, }; -use core::mem; #[cfg(target_os = "illumos")] type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; #[cfg(target_os = "solaris")] type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [mem::MaybeUninit]) -> Result<(), Error> { // getrandom(2) was introduced in Solaris 11.3 for Illumos in 2015. static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; if let Some(fptr) = GETRANDOM.ptr() { @@ -38,7 +39,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { // derived platforms for atomically obtaining random data. for chunk in dest.chunks_mut(256) { sys_fill_exact(chunk, |buf| unsafe { - func(buf.as_mut_ptr(), buf.len(), 0) as libc::ssize_t + func(buf.as_mut_ptr() as *mut u8, buf.len(), 0) as libc::ssize_t })? } Ok(()) diff --git a/src/solid.rs b/src/solid.rs index dc76aacb..85d17e3f 100644 --- a/src/solid.rs +++ b/src/solid.rs @@ -7,15 +7,17 @@ // except according to those terms. //! Implementation for SOLID -use crate::Error; +use core::mem::MaybeUninit; use core::num::NonZeroU32; +use crate::Error; + extern "C" { pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32; } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr(), dest.len()) }; +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr() as *mut u8, dest.len()) }; if ret >= 0 { Ok(()) } else { diff --git a/src/use_file.rs b/src/use_file.rs index 16c0216b..473091a0 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -7,15 +7,15 @@ // except according to those terms. //! Implementations that just need to read from a file +use core::cell::UnsafeCell; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + use crate::{ util::LazyUsize, util_libc::{open_readonly, sys_fill_exact}, Error, }; -use core::{ - cell::UnsafeCell, - sync::atomic::{AtomicUsize, Ordering::Relaxed}, -}; #[cfg(any( target_os = "dragonfly", @@ -29,9 +29,11 @@ const FILE_PATH: &str = "/dev/random\0"; #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] const FILE_PATH: &str = "/dev/urandom\0"; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; - let read = |buf: &mut [u8]| unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) }; + let read = |buf: &mut [MaybeUninit]| unsafe { + libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) + }; if cfg!(target_os = "emscripten") { // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes. diff --git a/src/util_libc.rs b/src/util_libc.rs index d057071a..8a2ab88b 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -6,14 +6,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] -use crate::Error; -use core::{ - num::NonZeroU32, - ptr::NonNull, - sync::atomic::{fence, AtomicPtr, Ordering}, -}; +use core::mem::MaybeUninit; +use core::num::NonZeroU32; +use core::ptr::NonNull; +use core::sync::atomic::{fence, AtomicPtr, Ordering}; + use libc::c_void; +use crate::Error; + cfg_if! { if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { use libc::__errno as errno_location; @@ -59,8 +60,8 @@ pub fn last_os_error() -> Error { // - should return -1 and set errno on failure // - should return the number of bytes written on success pub fn sys_fill_exact( - mut buf: &mut [u8], - sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t, + mut buf: &mut [MaybeUninit], + sys_fill: impl Fn(&mut [MaybeUninit]) -> libc::ssize_t, ) -> Result<(), Error> { while !buf.is_empty() { let res = sys_fill(buf); diff --git a/src/vxworks.rs b/src/vxworks.rs index 6cb5d52f..c0602931 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -7,10 +7,12 @@ // except according to those terms. //! Implementation for VxWorks -use crate::{util_libc::last_os_error, Error}; +use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering::Relaxed}; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +use crate::{util_libc::last_os_error, Error}; + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static RNG_INIT: AtomicBool = AtomicBool::new(false); while !RNG_INIT.load(Relaxed) { let ret = unsafe { libc::randSecure() }; @@ -25,7 +27,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { // Prevent overflow of i32 for chunk in dest.chunks_mut(i32::max_value() as usize) { - let ret = unsafe { libc::randABytes(chunk.as_mut_ptr(), chunk.len() as i32) }; + let ret = unsafe { + libc::randABytes(chunk.as_mut_ptr() as *mut libc::c_uchar, chunk.len() as i32) + }; if ret != 0 { return Err(last_os_error()); } diff --git a/src/wasi.rs b/src/wasi.rs index c5121824..51a5941a 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -11,9 +11,11 @@ use crate::Error; use core::num::NonZeroU32; use wasi::wasi_snapshot_preview1::random_get; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - match unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) } { - 0 => Ok(()), - err => Err(unsafe { NonZeroU32::new_unchecked(err as u32) }.into()), +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + let res = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) }; + if res == 0 { + Ok(()) + } else { + Err(unsafe { NonZeroU32::new_unchecked(res as u32) }.into()) } } diff --git a/src/windows.rs b/src/windows.rs index 41dc37a5..e532bfa8 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -6,8 +6,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::ffi::c_void; +use core::mem::MaybeUninit; +use core::num::NonZeroU32; +use core::ptr; + use crate::Error; -use core::{ffi::c_void, num::NonZeroU32, ptr}; const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; @@ -15,14 +19,16 @@ const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; extern "system" { fn BCryptGenRandom( hAlgorithm: *mut c_void, - pBuffer: *mut u8, + pBuffer: *mut MaybeUninit, cbBuffer: u32, dwFlags: u32, ) -> u32; } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of u32 + // Note: chunk cannot overflow isize::max_value() on 32bit systems + // because original slice cannot be longer than that. for chunk in dest.chunks_mut(u32::max_value() as usize) { // BCryptGenRandom was introduced in Windows Vista let ret = unsafe { @@ -38,6 +44,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { // We zeroize the highest bit, so the error code will reside // inside the range designated for OS codes. let code = ret ^ (1 << 31); + debug_assert_ne!(code, 0); // SAFETY: the second highest bit is always equal to one, // so it's impossible to get zero. Unfortunately the type // system does not have a way to express this yet. diff --git a/tests/rdrand.rs b/tests/rdrand.rs index 4ff85c47..949e47a5 100644 --- a/tests/rdrand.rs +++ b/tests/rdrand.rs @@ -11,5 +11,11 @@ mod rdrand; #[path = "../src/util.rs"] mod util; -use rdrand::getrandom_inner as getrandom_impl; +use rdrand::getrandom_inner; + +fn getrandom_impl(dest: &mut [u8]) -> Result<(), Error> { + getrandom_inner(unsafe { + core::slice::from_raw_parts_mut(dest.as_mut_ptr() as *mut _, dest.len()) + }) +} mod common;