| use crate::Error; | ||
| use rand_core::{TryCryptoRng, TryRngCore}; | ||
| /// A [`TryRngCore`] interface over the system's preferred random number source | ||
| /// | ||
| /// This is a zero-sized struct. It can be freely constructed with just `SysRng`. | ||
| /// | ||
| /// This struct is also available as [`rand::rngs::SysRng`] when using [rand]. | ||
| /// | ||
| /// # Usage example | ||
| /// | ||
| /// `SysRng` implements [`TryRngCore`]: | ||
| /// ``` | ||
| /// use getrandom::{rand_core::TryRngCore, SysRng}; | ||
| /// | ||
| /// let mut key = [0u8; 32]; | ||
| /// SysRng.try_fill_bytes(&mut key).unwrap(); | ||
| /// ``` | ||
| /// | ||
| /// Using it as an [`RngCore`] is possible using [`TryRngCore::unwrap_err`]: | ||
| /// ``` | ||
| /// use getrandom::rand_core::{TryRngCore, RngCore}; | ||
| /// use getrandom::SysRng; | ||
| /// | ||
| /// let mut rng = SysRng.unwrap_err(); | ||
| /// let random_u64 = rng.next_u64(); | ||
| /// ``` | ||
| /// | ||
| /// [rand]: https://crates.io/crates/rand | ||
| /// [`rand::rngs::SysRng`]: https://docs.rs/rand/latest/rand/rngs/struct.SysRng.html | ||
| /// [`RngCore`]: rand_core::RngCore | ||
| #[derive(Clone, Copy, Debug, Default)] | ||
| pub struct SysRng; | ||
| impl TryRngCore for SysRng { | ||
| type Error = Error; | ||
| #[inline] | ||
| fn try_next_u32(&mut self) -> Result<u32, Error> { | ||
| crate::u32() | ||
| } | ||
| #[inline] | ||
| fn try_next_u64(&mut self) -> Result<u64, Error> { | ||
| crate::u64() | ||
| } | ||
| #[inline] | ||
| fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { | ||
| crate::fill(dest) | ||
| } | ||
| } | ||
| impl TryCryptoRng for SysRng {} |
| cfg_if! { | ||
| if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] { | ||
| use libc::__errno as errno_location; | ||
| } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] { | ||
| use libc::__errno_location as errno_location; | ||
| } else if #[cfg(target_os = "illumos")] { | ||
| use libc::___errno as errno_location; | ||
| } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] { | ||
| use libc::__error as errno_location; | ||
| } else if #[cfg(target_os = "haiku")] { | ||
| use libc::_errnop as errno_location; | ||
| } else if #[cfg(target_os = "nto")] { | ||
| use libc::__get_errno_ptr as errno_location; | ||
| } else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] { | ||
| unsafe extern "C" { | ||
| // Not provided by libc: https://github.com/rust-lang/libc/issues/1995 | ||
| fn __errno() -> *mut libc::c_int; | ||
| } | ||
| use __errno as errno_location; | ||
| } else if #[cfg(target_os = "aix")] { | ||
| use libc::_Errno as errno_location; | ||
| } else { | ||
| compile_error!("errno_location is not provided for the target"); | ||
| } | ||
| } | ||
| pub(crate) fn get_errno() -> libc::c_int { | ||
| unsafe { core::ptr::read(errno_location()) } | ||
| } |
| //! Helpers built around pointer-sized atomics. | ||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| // This structure represents a lazily initialized static usize value. Useful | ||
| // when it is preferable to just rerun initialization instead of locking. | ||
| // unsync_init will invoke an init() function until it succeeds, then return the | ||
| // cached value for future calls. | ||
| // | ||
| // unsync_init supports init() "failing". If the init() method returns UNINIT, | ||
| // that value will be returned as normal, but will not be cached. | ||
| // | ||
| // Users should only depend on the _value_ returned by init() functions. | ||
| // Specifically, for the following init() function: | ||
| // fn init() -> usize { | ||
| // a(); | ||
| // let v = b(); | ||
| // c(); | ||
| // v | ||
| // } | ||
| // the effects of c() or writes to shared memory will not necessarily be | ||
| // observed and additional synchronization methods may be needed. | ||
| struct LazyUsize(AtomicUsize); | ||
| impl LazyUsize { | ||
| // The initialization is not completed. | ||
| const UNINIT: usize = usize::MAX; | ||
| const fn new() -> Self { | ||
| Self(AtomicUsize::new(Self::UNINIT)) | ||
| } | ||
| // Runs the init() function at most once, returning the value of some run of | ||
| // init(). Multiple callers can run their init() functions in parallel. | ||
| // init() should always return the same value, if it succeeds. | ||
| fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { | ||
| #[cold] | ||
| fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize { | ||
| let val = init(); | ||
| this.0.store(val, Ordering::Relaxed); | ||
| val | ||
| } | ||
| // Relaxed ordering is fine, as we only have a single atomic variable. | ||
| let val = self.0.load(Ordering::Relaxed); | ||
| if val != Self::UNINIT { | ||
| val | ||
| } else { | ||
| do_init(self, init) | ||
| } | ||
| } | ||
| } | ||
| // Identical to LazyUsize except with bool instead of usize. | ||
| pub(crate) struct LazyBool(LazyUsize); | ||
| impl LazyBool { | ||
| pub const fn new() -> Self { | ||
| Self(LazyUsize::new()) | ||
| } | ||
| pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { | ||
| self.0.unsync_init(|| usize::from(init())) != 0 | ||
| } | ||
| } |
| use core::mem::MaybeUninit; | ||
| /// Unpoisons `buf` if MSAN support is enabled. | ||
| /// | ||
| /// Most backends do not need to unpoison their output. Rust language- and | ||
| /// library- provided functionality unpoisons automatically. Similarly, libc | ||
| /// either natively supports MSAN and/or MSAN hooks libc-provided functions | ||
| /// to unpoison outputs on success. Only when all of these things are | ||
| /// bypassed do we need to do it ourselves. | ||
| /// | ||
| /// The call to unpoison should be done as close to the write as possible. | ||
| /// For example, if the backend partially fills the output buffer in chunks, | ||
| /// each chunk should be unpoisoned individually. This way, the correctness of | ||
| /// the chunking logic can be validated (in part) using MSAN. | ||
| pub unsafe fn unpoison(buf: &mut [MaybeUninit<u8>]) { | ||
| cfg_if! { | ||
| if #[cfg(getrandom_msan)] { | ||
| unsafe extern "C" { | ||
| fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); | ||
| } | ||
| let a = buf.as_mut_ptr().cast(); | ||
| let size = buf.len(); | ||
| unsafe { __msan_unpoison(a, size) }; | ||
| } else { | ||
| let _ = buf; | ||
| } | ||
| } | ||
| } |
| use crate::Error; | ||
| use core::mem::MaybeUninit; | ||
| mod get_errno; | ||
| mod sanitizer; | ||
| pub(crate) use get_errno::get_errno; | ||
| /// Fill a buffer by repeatedly invoking `sys_fill`. | ||
| /// | ||
| /// The `sys_fill` function: | ||
| /// - should return -1 and set errno on failure | ||
| /// - should return the number of bytes written on success | ||
| pub(crate) fn sys_fill_exact( | ||
| mut buf: &mut [MaybeUninit<u8>], | ||
| sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t, | ||
| ) -> Result<(), Error> { | ||
| while !buf.is_empty() { | ||
| let res = sys_fill(buf); | ||
| match res { | ||
| res if res > 0 => { | ||
| let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?; | ||
| let (l, r) = buf.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?; | ||
| unsafe { sanitizer::unpoison(l) }; | ||
| buf = r; | ||
| } | ||
| -1 => { | ||
| let errno = get_errno(); | ||
| // We should try again if the call was interrupted. | ||
| if errno != libc::EINTR { | ||
| return Err(Error::from_errno(errno)); | ||
| } | ||
| } | ||
| // Negative return codes not equal to -1 should be impossible. | ||
| // EOF (ret = 0) should be impossible, as the data we are reading | ||
| // should be an infinite stream of random bytes. | ||
| _ => return Err(Error::UNEXPECTED), | ||
| } | ||
| } | ||
| Ok(()) | ||
| } |
| #![cfg(feature = "sys_rng")] | ||
| use getrandom::SysRng; | ||
| use getrandom::rand_core::TryRngCore; | ||
| #[test] | ||
| fn test_sys_rng() { | ||
| let x = SysRng.try_next_u64().unwrap(); | ||
| let y = SysRng.try_next_u64().unwrap(); | ||
| assert!(x != 0); | ||
| assert!(x != y); | ||
| } | ||
| #[test] | ||
| fn test_construction() { | ||
| assert!(SysRng.try_next_u64().unwrap() != 0); | ||
| } |
| { | ||
| "git": { | ||
| "sha1": "38e4ad38309a85b56eef4fc759535ccfc322ba9a" | ||
| "sha1": "78536276778a84f92a0ffc712401b581c6bfb354" | ||
| }, | ||
| "path_in_vcs": "" | ||
| } |
@@ -5,3 +5,3 @@ #![feature(test, maybe_uninit_uninit_array_transpose)] | ||
| use std::{ | ||
| mem::{size_of, MaybeUninit}, | ||
| mem::{MaybeUninit, size_of}, | ||
| slice, | ||
@@ -8,0 +8,0 @@ }; |
+0
-48
@@ -1,33 +0,1 @@ | ||
| use std::{env, ffi::OsString, process::Command}; | ||
| /// Tries to get the minor version of the Rust compiler in use. | ||
| /// If it fails for any reason, returns `None`. | ||
| /// | ||
| /// Based on the `rustc_version` crate. | ||
| fn rustc_minor_version() -> Option<u64> { | ||
| let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); | ||
| let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER").filter(|w| !w.is_empty()) { | ||
| let mut cmd = Command::new(wrapper); | ||
| cmd.arg(rustc); | ||
| cmd | ||
| } else { | ||
| Command::new(rustc) | ||
| }; | ||
| let out = cmd.arg("-vV").output().ok()?; | ||
| if !out.status.success() { | ||
| return None; | ||
| } | ||
| let stdout = std::str::from_utf8(&out.stdout).ok()?; | ||
| // Assumes that the first line contains "rustc 1.xx.0-channel (abcdef 2025-01-01)" | ||
| // where "xx" is the minor version which we want to extract | ||
| let mut lines = stdout.lines(); | ||
| let first_line = lines.next()?; | ||
| let minor_ver_str = first_line.split('.').nth(1)?; | ||
| minor_ver_str.parse().ok() | ||
| } | ||
| fn main() { | ||
@@ -41,18 +9,2 @@ // Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't | ||
| } | ||
| // Use `RtlGenRandom` on older compiler versions since win7 targets | ||
| // TODO(MSRV 1.78): Remove this check | ||
| let target_family = env::var_os("CARGO_CFG_TARGET_FAMILY").and_then(|f| f.into_string().ok()); | ||
| if target_family.as_deref() == Some("windows") { | ||
| /// Minor version of the Rust compiler in which win7 targets were inroduced | ||
| const WIN7_INTRODUCED_MINOR_VER: u64 = 78; | ||
| match rustc_minor_version() { | ||
| Some(minor_ver) if minor_ver < WIN7_INTRODUCED_MINOR_VER => { | ||
| println!("cargo:rustc-cfg=getrandom_backend=\"windows_legacy\""); | ||
| } | ||
| None => println!("cargo:warning=Couldn't detect minor version of the Rust compiler"), | ||
| _ => {} | ||
| } | ||
| } | ||
| } |
+175
-58
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 3 | ||
| version = 4 | ||
| [[package]] | ||
| name = "async-trait" | ||
| version = "0.1.89" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "autocfg" | ||
| version = "1.5.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | ||
| [[package]] | ||
| name = "bumpalo" | ||
| version = "3.19.0" | ||
| version = "3.19.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" | ||
| checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" | ||
| [[package]] | ||
| name = "cast" | ||
| version = "0.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" | ||
| [[package]] | ||
| name = "cc" | ||
| version = "1.2.41" | ||
| version = "1.2.51" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" | ||
| checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" | ||
| dependencies = [ | ||
@@ -23,15 +46,15 @@ "find-msvc-tools", | ||
| name = "cfg-if" | ||
| version = "1.0.3" | ||
| version = "1.0.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" | ||
| checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | ||
| [[package]] | ||
| name = "find-msvc-tools" | ||
| version = "0.1.4" | ||
| version = "0.1.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" | ||
| checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" | ||
| [[package]] | ||
| name = "getrandom" | ||
| version = "0.3.4" | ||
| version = "0.4.0-rc.0" | ||
| dependencies = [ | ||
@@ -42,2 +65,3 @@ "cfg-if", | ||
| "r-efi", | ||
| "rand_core", | ||
| "wasip2", | ||
@@ -49,6 +73,12 @@ "wasm-bindgen", | ||
| [[package]] | ||
| name = "itoa" | ||
| version = "1.0.17" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" | ||
| [[package]] | ||
| name = "js-sys" | ||
| version = "0.3.80" | ||
| version = "0.3.83" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" | ||
| checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" | ||
| dependencies = [ | ||
@@ -61,17 +91,23 @@ "once_cell", | ||
| name = "libc" | ||
| version = "0.2.177" | ||
| version = "0.2.178" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" | ||
| checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" | ||
| [[package]] | ||
| name = "log" | ||
| version = "0.4.28" | ||
| name = "libm" | ||
| version = "0.2.15" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" | ||
| checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" | ||
| [[package]] | ||
| name = "memchr" | ||
| version = "2.7.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" | ||
| [[package]] | ||
| name = "minicov" | ||
| version = "0.3.7" | ||
| version = "0.3.8" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" | ||
| checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d" | ||
| dependencies = [ | ||
@@ -83,2 +119,21 @@ "cc", | ||
| [[package]] | ||
| name = "nu-ansi-term" | ||
| version = "0.50.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" | ||
| dependencies = [ | ||
| "windows-sys", | ||
| ] | ||
| [[package]] | ||
| name = "num-traits" | ||
| version = "0.2.19" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | ||
| dependencies = [ | ||
| "autocfg", | ||
| "libm", | ||
| ] | ||
| [[package]] | ||
| name = "once_cell" | ||
@@ -90,6 +145,12 @@ version = "1.21.3" | ||
| [[package]] | ||
| name = "oorandom" | ||
| version = "11.1.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" | ||
| [[package]] | ||
| name = "proc-macro2" | ||
| version = "1.0.101" | ||
| version = "1.0.103" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" | ||
| checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" | ||
| dependencies = [ | ||
@@ -101,5 +162,5 @@ "unicode-ident", | ||
| name = "quote" | ||
| version = "1.0.41" | ||
| version = "1.0.42" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" | ||
| checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" | ||
| dependencies = [ | ||
@@ -116,2 +177,14 @@ "proc-macro2", | ||
| [[package]] | ||
| name = "rand_core" | ||
| version = "0.10.0-rc-3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f66ee92bc15280519ef199a274fe0cafff4245d31bc39aaa31c011ad56cb1f05" | ||
| [[package]] | ||
| name = "rustversion" | ||
| version = "1.0.22" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" | ||
| [[package]] | ||
| name = "same-file" | ||
@@ -126,2 +199,45 @@ version = "1.0.6" | ||
| [[package]] | ||
| name = "serde" | ||
| version = "1.0.228" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" | ||
| dependencies = [ | ||
| "serde_core", | ||
| "serde_derive", | ||
| ] | ||
| [[package]] | ||
| name = "serde_core" | ||
| version = "1.0.228" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" | ||
| dependencies = [ | ||
| "serde_derive", | ||
| ] | ||
| [[package]] | ||
| name = "serde_derive" | ||
| version = "1.0.228" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "serde_json" | ||
| version = "1.0.148" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" | ||
| dependencies = [ | ||
| "itoa", | ||
| "memchr", | ||
| "serde", | ||
| "serde_core", | ||
| "zmij", | ||
| ] | ||
| [[package]] | ||
| name = "shlex" | ||
@@ -134,5 +250,5 @@ version = "1.3.0" | ||
| name = "syn" | ||
| version = "2.0.106" | ||
| version = "2.0.111" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" | ||
| checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" | ||
| dependencies = [ | ||
@@ -146,5 +262,5 @@ "proc-macro2", | ||
| name = "unicode-ident" | ||
| version = "1.0.19" | ||
| version = "1.0.22" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" | ||
| checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" | ||
@@ -172,8 +288,9 @@ [[package]] | ||
| name = "wasm-bindgen" | ||
| version = "0.2.103" | ||
| version = "0.2.106" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" | ||
| checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "once_cell", | ||
| "rustversion", | ||
| "wasm-bindgen-macro", | ||
@@ -184,20 +301,6 @@ "wasm-bindgen-shared", | ||
| [[package]] | ||
| name = "wasm-bindgen-backend" | ||
| version = "0.2.103" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" | ||
| dependencies = [ | ||
| "bumpalo", | ||
| "log", | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-shared", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-futures" | ||
| version = "0.4.53" | ||
| version = "0.4.56" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" | ||
| checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" | ||
| dependencies = [ | ||
@@ -213,5 +316,5 @@ "cfg-if", | ||
| name = "wasm-bindgen-macro" | ||
| version = "0.2.103" | ||
| version = "0.2.106" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" | ||
| checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" | ||
| dependencies = [ | ||
@@ -224,10 +327,10 @@ "quote", | ||
| name = "wasm-bindgen-macro-support" | ||
| version = "0.2.103" | ||
| version = "0.2.106" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" | ||
| checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" | ||
| dependencies = [ | ||
| "bumpalo", | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-backend", | ||
| "wasm-bindgen-shared", | ||
@@ -238,5 +341,5 @@ ] | ||
| name = "wasm-bindgen-shared" | ||
| version = "0.2.103" | ||
| version = "0.2.106" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" | ||
| checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" | ||
| dependencies = [ | ||
@@ -248,8 +351,16 @@ "unicode-ident", | ||
| name = "wasm-bindgen-test" | ||
| version = "0.3.53" | ||
| version = "0.3.56" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c" | ||
| checksum = "25e90e66d265d3a1efc0e72a54809ab90b9c0c515915c67cdf658689d2c22c6c" | ||
| dependencies = [ | ||
| "async-trait", | ||
| "cast", | ||
| "js-sys", | ||
| "libm", | ||
| "minicov", | ||
| "nu-ansi-term", | ||
| "num-traits", | ||
| "oorandom", | ||
| "serde", | ||
| "serde_json", | ||
| "wasm-bindgen", | ||
@@ -262,5 +373,5 @@ "wasm-bindgen-futures", | ||
| name = "wasm-bindgen-test-macro" | ||
| version = "0.3.53" | ||
| version = "0.3.56" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" | ||
| checksum = "7150335716dce6028bead2b848e72f47b45e7b9422f64cccdc23bedca89affc1" | ||
| dependencies = [ | ||
@@ -274,5 +385,5 @@ "proc-macro2", | ||
| name = "web-sys" | ||
| version = "0.3.80" | ||
| version = "0.3.83" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" | ||
| checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" | ||
| dependencies = [ | ||
@@ -312,1 +423,7 @@ "js-sys", | ||
| checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" | ||
| [[package]] | ||
| name = "zmij" | ||
| version = "1.0.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e6d6085d62852e35540689d1f97ad663e3971fc19cf5eceab364d62c646ea167" |
+16
-4
@@ -13,6 +13,6 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| [package] | ||
| edition = "2021" | ||
| rust-version = "1.63" | ||
| edition = "2024" | ||
| rust-version = "1.85" | ||
| name = "getrandom" | ||
| version = "0.3.4" | ||
| version = "0.4.0-rc.0" | ||
| authors = ["The Rand Project Developers"] | ||
@@ -37,3 +37,6 @@ build = "build.rs" | ||
| [package.metadata.docs.rs] | ||
| features = ["std"] | ||
| features = [ | ||
| "std", | ||
| "sys_rng", | ||
| ] | ||
@@ -52,2 +55,3 @@ [package.metadata.cross.target.x86_64-unknown-netbsd] | ||
| std = [] | ||
| sys_rng = ["dep:rand_core"] | ||
| wasm_js = [ | ||
@@ -66,2 +70,6 @@ "dep:wasm-bindgen", | ||
| [[test]] | ||
| name = "sys_rng" | ||
| path = "tests/sys_rng.rs" | ||
| [[bench]] | ||
@@ -74,2 +82,6 @@ name = "buffer" | ||
| [dependencies.rand_core] | ||
| version = "0.10.0-rc-3" | ||
| optional = true | ||
| [target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies.libc] | ||
@@ -76,0 +88,0 @@ version = "0.2.154" |
+15
-1
| # Changelog | ||
| All notable changes to this project will be documented in this file. | ||
| The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) | ||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) | ||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
| ## [Unreleased] | ||
| ### Added | ||
| - `RawOsError` type alias [#739] | ||
| - `SysRng` behind new feature `sys_rng` [#751] | ||
| ### Changed | ||
| - Use Edition 2024 and MSRV 1.85 [#749] | ||
| [#739]: https://github.com/rust-random/getrandom/pull/739 | ||
| [#749]: https://github.com/rust-random/getrandom/pull/749 | ||
| [#751]: https://github.com/rust-random/getrandom/pull/751 | ||
| ## [0.3.4] - 2025-10-14 | ||
@@ -634,2 +647,3 @@ | ||
| [Unreleased]: https://github.com/rust-random/getrandom/compare/v0.3.4...master | ||
| [0.3.4]: https://github.com/rust-random/getrandom/compare/v0.3.3...v0.3.4 | ||
@@ -636,0 +650,0 @@ [0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 |
+3
-3
@@ -162,3 +162,3 @@ # getrandom: system's random number generator | ||
| #[no_mangle] | ||
| #[unsafe(no_mangle)] | ||
| unsafe extern "Rust" fn __getrandom_v03_custom( | ||
@@ -193,3 +193,3 @@ dest: *mut u8, | ||
| #[no_mangle] | ||
| #[unsafe(no_mangle)] | ||
| unsafe extern "Rust" fn __getrandom_v03_custom( | ||
@@ -307,3 +307,3 @@ dest: *mut u8, | ||
| This crate requires Rust 1.63 or later. | ||
| This crate requires Rust 1.85 or later. | ||
@@ -310,0 +310,0 @@ ## License |
+0
-6
@@ -16,7 +16,5 @@ //! System-specific implementations. | ||
| mod getrandom; | ||
| mod sanitizer; | ||
| pub use getrandom::*; | ||
| } else if #[cfg(getrandom_backend = "linux_raw")] { | ||
| mod linux_raw; | ||
| mod sanitizer; | ||
| pub use linux_raw::*; | ||
@@ -53,3 +51,2 @@ } else if #[cfg(getrandom_backend = "rdrand")] { | ||
| mod linux_raw; | ||
| mod sanitizer; | ||
| pub use linux_raw::*; | ||
@@ -122,3 +119,2 @@ } else if #[cfg(target_os = "espidf")] { | ||
| mod linux_android_with_fallback; | ||
| mod sanitizer; | ||
| pub use linux_android_with_fallback::*; | ||
@@ -138,4 +134,2 @@ } else if #[cfg(any( | ||
| mod getrandom; | ||
| #[cfg(any(target_os = "android", target_os = "linux"))] | ||
| mod sanitizer; | ||
| pub use getrandom::*; | ||
@@ -142,0 +136,0 @@ } else if #[cfg(target_os = "solaris")] { |
@@ -9,3 +9,3 @@ //! An implementation which calls out to an externally defined function. | ||
| pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
| extern "Rust" { | ||
| unsafe extern "Rust" { | ||
| fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>; | ||
@@ -12,0 +12,0 @@ } |
@@ -5,3 +5,3 @@ //! Implementation for UEFI using EFI_RNG_PROTOCOL | ||
| mem::MaybeUninit, | ||
| ptr::{self, null_mut, NonNull}, | ||
| ptr::{self, NonNull, null_mut}, | ||
| sync::atomic::{AtomicPtr, Ordering::Relaxed}, | ||
@@ -8,0 +8,0 @@ }; |
@@ -7,3 +7,3 @@ //! Implementation for ESP-IDF | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; | ||
@@ -10,0 +10,0 @@ } |
@@ -8,3 +8,3 @@ //! Implementation for Fuchsia Zircon | ||
| #[link(name = "zircon")] | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| fn zx_cprng_draw(buffer: *mut u8, length: usize); | ||
@@ -11,0 +11,0 @@ } |
@@ -15,4 +15,4 @@ //! Implementation using getentropy(2) | ||
| #[path = "../util_libc.rs"] | ||
| mod util_libc; | ||
| #[path = "../utils/get_errno.rs"] | ||
| mod utils; | ||
@@ -24,3 +24,4 @@ #[inline] | ||
| if ret != 0 { | ||
| return Err(util_libc::last_os_error()); | ||
| let errno = utils::get_errno(); | ||
| return Err(Error::from_errno(errno)); | ||
| } | ||
@@ -27,0 +28,0 @@ } |
@@ -23,18 +23,10 @@ //! Implementation using getrandom(2). | ||
| #[path = "../util_libc.rs"] | ||
| mod util_libc; | ||
| #[path = "../utils/sys_fill_exact.rs"] | ||
| mod utils; | ||
| #[inline] | ||
| pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
| util_libc::sys_fill_exact(dest, |buf| unsafe { | ||
| let ret = libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0); | ||
| #[cfg(any(target_os = "android", target_os = "linux"))] | ||
| #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. | ||
| unsafe { | ||
| super::sanitizer::unpoison_linux_getrandom_result(buf, ret); | ||
| } | ||
| ret | ||
| utils::sys_fill_exact(dest, |buf| unsafe { | ||
| libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) | ||
| }) | ||
| } |
@@ -5,3 +5,3 @@ //! Implementation for Hermit | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize; | ||
@@ -8,0 +8,0 @@ // Note that `sys_secure_rand32/64` are implemented using `sys_read_entropy`: |
| //! Implementation for Linux / Android with `/dev/urandom` fallback | ||
| use super::{sanitizer, use_file}; | ||
| use super::use_file; | ||
| use crate::Error; | ||
| use core::{ | ||
| ffi::c_void, | ||
| mem::{transmute, MaybeUninit}, | ||
| mem::{MaybeUninit, transmute}, | ||
| ptr::NonNull, | ||
| sync::atomic::{AtomicPtr, Ordering}, | ||
| }; | ||
| use use_file::util_libc; | ||
| use use_file::utils; | ||
@@ -47,4 +47,4 @@ pub use crate::util::{inner_u32, inner_u64}; | ||
| } else if res.is_negative() { | ||
| match util_libc::last_os_error().raw_os_error() { | ||
| Some(libc::ENOSYS) => NOT_AVAILABLE, // No kernel support | ||
| match utils::get_errno() { | ||
| libc::ENOSYS => NOT_AVAILABLE, // No kernel support | ||
| // The fallback on EPERM is intentionally not done on Android since this workaround | ||
@@ -54,3 +54,3 @@ // seems to be needed only for specific Linux-based products that aren't based | ||
| #[cfg(target_os = "linux")] | ||
| Some(libc::EPERM) => NOT_AVAILABLE, // Blocked by seccomp | ||
| libc::EPERM => NOT_AVAILABLE, // Blocked by seccomp | ||
| _ => fptr, | ||
@@ -99,8 +99,6 @@ } | ||
| let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) }; | ||
| util_libc::sys_fill_exact(dest, |buf| unsafe { | ||
| let ret = getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0); | ||
| sanitizer::unpoison_linux_getrandom_result(buf, ret); | ||
| ret | ||
| utils::sys_fill_exact(dest, |buf| unsafe { | ||
| getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0) | ||
| }) | ||
| } | ||
| } |
+101
-75
| //! Implementation for Linux / Android using `asm!`-based syscalls. | ||
| use super::sanitizer; | ||
| pub use crate::util::{inner_u32, inner_u64}; | ||
@@ -9,2 +8,5 @@ use crate::{Error, MaybeUninit}; | ||
| #[path = "../utils/sanitizer.rs"] | ||
| mod utils; | ||
| #[allow(non_upper_case_globals)] | ||
@@ -16,4 +18,7 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { | ||
| cfg_if! { | ||
| if #[cfg(target_arch = "arm")] { | ||
| // TODO(MSRV-1.78): Also check `target_abi = "eabi"`. | ||
| if #[cfg(all( | ||
| target_arch = "arm", | ||
| any(target_abi = "eabi", target_abi = "eabihf"), | ||
| ))] { | ||
| const __NR_getrandom: u32 = 384; | ||
| // In thumb-mode, r7 is the frame pointer and is not permitted to be used in | ||
@@ -25,16 +30,20 @@ // an inline asm operand, so we have to use a different register and copy it | ||
| // bother with it. | ||
| core::arch::asm!( | ||
| "mov {tmp}, r7", | ||
| // TODO(MSRV-1.82): replace with `nr = const __NR_getrandom,` | ||
| "mov r7, #384", | ||
| "svc 0", | ||
| "mov r7, {tmp}", | ||
| tmp = out(reg) _, | ||
| inlateout("r0") buf => r0, | ||
| in("r1") buflen, | ||
| in("r2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } else if #[cfg(target_arch = "aarch64")] { | ||
| // TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above. | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "mov {tmp}, r7", | ||
| "mov r7, {nr}", | ||
| "svc 0", | ||
| "mov r7, {tmp}", | ||
| tmp = out(reg) _, | ||
| nr = const __NR_getrandom, | ||
| inlateout("r0") buf => r0, | ||
| in("r1") buflen, | ||
| in("r2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(all( | ||
| target_arch = "aarch64", | ||
| any(target_abi = "", target_abi = "ilp32"), | ||
| ))] { | ||
| // According to the ILP32 patch for the kernel that hasn't yet | ||
@@ -45,41 +54,51 @@ // been merged into the mainline, "AARCH64/ILP32 ABI uses standard | ||
| const __NR_getrandom: u32 = 278; | ||
| core::arch::asm!( | ||
| "svc 0", | ||
| in("x8") __NR_getrandom, | ||
| inlateout("x0") buf => r0, | ||
| in("x1") buflen, | ||
| in("x2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } else if #[cfg(target_arch = "loongarch64")] { | ||
| // TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above. | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "svc 0", | ||
| in("x8") __NR_getrandom, | ||
| inlateout("x0") buf => r0, | ||
| in("x1") buflen, | ||
| in("x2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(all( | ||
| target_arch = "loongarch64", | ||
| any(target_abi = "", target_abi = "ilp32"), | ||
| ))] { | ||
| const __NR_getrandom: u32 = 278; | ||
| core::arch::asm!( | ||
| "syscall 0", | ||
| in("$a7") __NR_getrandom, | ||
| inlateout("$a0") buf => r0, | ||
| in("$a1") buflen, | ||
| in("$a2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "syscall 0", | ||
| in("$a7") __NR_getrandom, | ||
| inlateout("$a0") buf => r0, | ||
| in("$a1") buflen, | ||
| in("$a2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { | ||
| const __NR_getrandom: u32 = 278; | ||
| core::arch::asm!( | ||
| "ecall", | ||
| in("a7") __NR_getrandom, | ||
| inlateout("a0") buf => r0, | ||
| in("a1") buflen, | ||
| in("a2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "ecall", | ||
| in("a7") __NR_getrandom, | ||
| inlateout("a0") buf => r0, | ||
| in("a1") buflen, | ||
| in("a2") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(target_arch = "s390x")] { | ||
| const __NR_getrandom: u32 = 349; | ||
| core::arch::asm!( | ||
| "svc 0", | ||
| in("r1") __NR_getrandom, | ||
| inlateout("r2") buf => r0, | ||
| in("r3") buflen, | ||
| in("r4") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "svc 0", | ||
| in("r1") __NR_getrandom, | ||
| inlateout("r2") buf => r0, | ||
| in("r3") buflen, | ||
| in("r4") flags, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(target_arch = "x86")] { | ||
@@ -90,13 +109,17 @@ const __NR_getrandom: u32 = 355; | ||
| // so we use the simple "legacy" way of doing syscalls. | ||
| core::arch::asm!( | ||
| "int $$0x80", | ||
| in("eax") __NR_getrandom, | ||
| in("ebx") buf, | ||
| in("ecx") buflen, | ||
| in("edx") flags, | ||
| lateout("eax") r0, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } else if #[cfg(target_arch = "x86_64")] { | ||
| // TODO(MSRV-1.78): Add `any(target_abi = "", target_abi = "x32")` above. | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "int $$0x80", | ||
| in("eax") __NR_getrandom, | ||
| in("ebx") buf, | ||
| in("ecx") buflen, | ||
| in("edx") flags, | ||
| lateout("eax") r0, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else if #[cfg(all( | ||
| target_arch = "x86_64", | ||
| any(target_abi = "", target_abi = "x32"), | ||
| ))] { | ||
| const __X32_SYSCALL_BIT: u32 = 0x40000000; | ||
@@ -106,13 +129,15 @@ const OFFSET: u32 = if cfg!(target_pointer_width = "32") { __X32_SYSCALL_BIT } else { 0 }; | ||
| core::arch::asm!( | ||
| "syscall", | ||
| in("rax") __NR_getrandom, | ||
| in("rdi") buf, | ||
| in("rsi") buflen, | ||
| in("rdx") flags, | ||
| lateout("rax") r0, | ||
| lateout("rcx") _, | ||
| lateout("r11") _, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| unsafe { | ||
| core::arch::asm!( | ||
| "syscall", | ||
| in("rax") __NR_getrandom, | ||
| in("rdi") buf, | ||
| in("rsi") buflen, | ||
| in("rdx") flags, | ||
| lateout("rax") r0, | ||
| lateout("rcx") _, | ||
| lateout("r11") _, | ||
| options(nostack, preserves_flags) | ||
| ); | ||
| } | ||
| } else { | ||
@@ -133,7 +158,8 @@ compile_error!("`linux_raw` backend does not support this target arch"); | ||
| let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) }; | ||
| unsafe { sanitizer::unpoison_linux_getrandom_result(dest, ret) }; | ||
| match usize::try_from(ret) { | ||
| Ok(0) => return Err(Error::UNEXPECTED), | ||
| Ok(len) => { | ||
| dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?; | ||
| let (l, r) = dest.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?; | ||
| unsafe { utils::unpoison(l) }; | ||
| dest = r; | ||
| if dest.is_empty() { | ||
@@ -140,0 +166,0 @@ return Ok(()); |
@@ -17,4 +17,4 @@ //! Implementation for NetBSD | ||
| #[path = "../util_libc.rs"] | ||
| mod util_libc; | ||
| #[path = "../utils/sys_fill_exact.rs"] | ||
| mod utils; | ||
@@ -76,5 +76,5 @@ unsafe extern "C" fn polyfill_using_kern_arand( | ||
| let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) }; | ||
| util_libc::sys_fill_exact(dest, |buf| unsafe { | ||
| utils::sys_fill_exact(dest, |buf| unsafe { | ||
| fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0) | ||
| }) | ||
| } |
+26
-13
| //! RDRAND backend for x86(-64) targets | ||
| use crate::{util::slice_as_uninit, Error}; | ||
| use core::mem::{size_of, MaybeUninit}; | ||
| use crate::{Error, util::slice_as_uninit}; | ||
| use core::mem::{MaybeUninit, size_of}; | ||
| #[path = "../lazy.rs"] | ||
| #[path = "../utils/lazy.rs"] | ||
| mod lazy; | ||
@@ -31,6 +31,16 @@ | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand() -> Option<Word> { | ||
| fn rdrand() -> Option<Word> { | ||
| for _ in 0..RETRY_LIMIT { | ||
| let mut val = 0; | ||
| if rdrand_step(&mut val) == 1 { | ||
| // SAFETY: this function is safe to call from a `[target_feature(enable | ||
| // = "rdrand")]` context (it itself is annotated with | ||
| // `target_feature(enable = "rdrand")`) but was marked unsafe until | ||
| // https://github.com/rust-lang/stdarch/commit/59864cd which was pulled | ||
| // in via https://github.com/rust-lang/rust/commit/f2eb88b which is | ||
| // expected to be included in 1.93.0. Since our MSRV is 1.85, we need to | ||
| // use unsafe here and suppress the lint. | ||
| // | ||
| // TODO(MSRV 1.93): remove allow(unused_unsafe) and the unsafe block. | ||
| #[allow(unused_unsafe)] | ||
| if unsafe { rdrand_step(&mut val) } == 1 { | ||
| return Some(val); | ||
@@ -52,5 +62,5 @@ } | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn self_test() -> bool { | ||
| fn self_test() -> bool { | ||
| // On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision. | ||
| let mut prev = !0; // TODO(MSRV 1.43): Move to usize::MAX | ||
| let mut prev = Word::MAX; | ||
| let mut fails = 0; | ||
@@ -72,2 +82,5 @@ for _ in 0..8 { | ||
| // check that leaf 1 is supported before using it. | ||
| // | ||
| // TODO(MSRV 1.94): remove allow(unused_unsafe) and the unsafe blocks for `__cpuid`. | ||
| #[allow(unused_unsafe)] | ||
| let cpuid0 = unsafe { arch::__cpuid(0) }; | ||
@@ -77,2 +90,3 @@ if cpuid0.eax < 1 { | ||
| } | ||
| #[allow(unused_unsafe)] | ||
| let cpuid1 = unsafe { arch::__cpuid(1) }; | ||
@@ -108,5 +122,4 @@ | ||
| // TODO: make this function safe when we have feature(target_feature_11) | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> { | ||
| fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> { | ||
| // We use chunks_exact_mut instead of chunks_mut as it allows almost all | ||
@@ -131,3 +144,3 @@ // calls to memcpy to be elided by the compiler. | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand_u32() -> Option<u32> { | ||
| fn rdrand_u32() -> Option<u32> { | ||
| rdrand().map(crate::util::truncate) | ||
@@ -138,3 +151,3 @@ } | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand_u64() -> Option<u64> { | ||
| fn rdrand_u64() -> Option<u64> { | ||
| rdrand() | ||
@@ -145,3 +158,3 @@ } | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand_u32() -> Option<u32> { | ||
| fn rdrand_u32() -> Option<u32> { | ||
| rdrand() | ||
@@ -152,3 +165,3 @@ } | ||
| #[target_feature(enable = "rdrand")] | ||
| unsafe fn rdrand_u64() -> Option<u64> { | ||
| fn rdrand_u64() -> Option<u64> { | ||
| let a = rdrand()?; | ||
@@ -155,0 +168,0 @@ let b = rdrand()?; |
+13
-11
@@ -6,7 +6,7 @@ //! RNDR register backend for aarch64 targets | ||
| use crate::{ | ||
| Error, | ||
| util::{slice_as_uninit, truncate}, | ||
| Error, | ||
| }; | ||
| use core::arch::asm; | ||
| use core::mem::{size_of, MaybeUninit}; | ||
| use core::mem::{MaybeUninit, size_of}; | ||
@@ -31,8 +31,10 @@ #[cfg(not(target_arch = "aarch64"))] | ||
| // AArch64 RNDR register is accessible by s3_3_c2_c4_0 | ||
| asm!( | ||
| "mrs {x}, RNDR", | ||
| "mrs {nzcv}, NZCV", | ||
| x = out(reg) x, | ||
| nzcv = out(reg) nzcv, | ||
| ); | ||
| unsafe { | ||
| asm!( | ||
| "mrs {x}, RNDR", | ||
| "mrs {nzcv}, NZCV", | ||
| x = out(reg) x, | ||
| nzcv = out(reg) nzcv, | ||
| ); | ||
| } | ||
@@ -52,3 +54,3 @@ // If the hardware returns a genuine random number, PSTATE.NZCV is set to 0b0000 | ||
| for chunk in chunks.by_ref() { | ||
| let src = rndr()?.to_ne_bytes(); | ||
| let src = unsafe { rndr() }?.to_ne_bytes(); | ||
| chunk.copy_from_slice(slice_as_uninit(&src)); | ||
@@ -60,3 +62,3 @@ } | ||
| if n > 0 { | ||
| let src = rndr()?.to_ne_bytes(); | ||
| let src = unsafe { rndr() }?.to_ne_bytes(); | ||
| tail.copy_from_slice(slice_as_uninit(&src[..n])); | ||
@@ -74,3 +76,3 @@ } | ||
| fn is_rndr_available() -> bool { | ||
| #[path = "../lazy.rs"] | ||
| #[path = "../utils/lazy.rs"] | ||
| mod lazy; | ||
@@ -77,0 +79,0 @@ static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); |
@@ -17,8 +17,6 @@ //! Solaris implementation using getrandom(2). | ||
| use core::{ffi::c_void, mem::MaybeUninit}; | ||
| use libc::___errno as errno_location; | ||
| pub use crate::util::{inner_u32, inner_u64}; | ||
| #[path = "../util_libc.rs"] | ||
| mod util_libc; | ||
| const MAX_BYTES: usize = 1024; | ||
@@ -37,3 +35,6 @@ | ||
| // The syscall failed. | ||
| Ok(0) => return Err(util_libc::last_os_error()), | ||
| Ok(0) => { | ||
| let errno = unsafe { core::ptr::read(errno_location()) }; | ||
| return Err(Error::from_errno(errno)); | ||
| } | ||
| // All other cases should be impossible. | ||
@@ -40,0 +41,0 @@ _ => return Err(Error::UNEXPECTED), |
@@ -7,3 +7,3 @@ //! Implementation for SOLID | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32; | ||
@@ -10,0 +10,0 @@ } |
+17
-28
| //! Implementations that just need to read from a file | ||
| use crate::Error; | ||
| use core::{ | ||
| ffi::c_void, | ||
| ffi::{CStr, c_void}, | ||
| mem::MaybeUninit, | ||
@@ -12,4 +12,4 @@ sync::atomic::{AtomicI32, Ordering}, | ||
| #[path = "../util_libc.rs"] | ||
| pub(super) mod util_libc; | ||
| #[path = "../utils/sys_fill_exact.rs"] | ||
| pub(super) mod utils; | ||
@@ -22,3 +22,3 @@ /// For all platforms, we use `/dev/urandom` rather than `/dev/random`. | ||
| /// - On Haiku and QNX Neutrino they are identical. | ||
| const FILE_PATH: &[u8] = b"/dev/urandom\0"; | ||
| const FILE_PATH: &CStr = c"/dev/urandom"; | ||
@@ -51,3 +51,3 @@ // File descriptor is a "nonnegative integer", so we can safely use negative sentinel values. | ||
| } | ||
| util_libc::sys_fill_exact(dest, |buf| unsafe { | ||
| utils::sys_fill_exact(dest, |buf| unsafe { | ||
| libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len()) | ||
@@ -58,23 +58,12 @@ }) | ||
| /// Open a file in read-only mode. | ||
| /// | ||
| /// # Panics | ||
| /// If `path` does not contain any zeros. | ||
| // TODO: Move `path` to `CStr` and use `CStr::from_bytes_until_nul` (MSRV 1.69) | ||
| // or C-string literals (MSRV 1.77) for statics | ||
| fn open_readonly(path: &[u8]) -> Result<libc::c_int, Error> { | ||
| assert!(path.contains(&0)); | ||
| fn open_readonly(path: &CStr) -> Result<libc::c_int, Error> { | ||
| loop { | ||
| let fd = unsafe { | ||
| libc::open( | ||
| path.as_ptr().cast::<libc::c_char>(), | ||
| libc::O_RDONLY | libc::O_CLOEXEC, | ||
| ) | ||
| }; | ||
| let fd = unsafe { libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_CLOEXEC) }; | ||
| if fd >= 0 { | ||
| return Ok(fd); | ||
| } | ||
| let err = util_libc::last_os_error(); | ||
| let errno = utils::get_errno(); | ||
| // We should try again if open() was interrupted. | ||
| if err.raw_os_error() != Some(libc::EINTR) { | ||
| return Err(err); | ||
| if errno != libc::EINTR { | ||
| return Err(Error::from_errno(errno)); | ||
| } | ||
@@ -154,3 +143,3 @@ } | ||
| mod sync { | ||
| use super::{open_readonly, util_libc::last_os_error, Error, FD, FD_ONGOING_INIT}; | ||
| use super::{Error, FD, FD_ONGOING_INIT, open_readonly, utils}; | ||
@@ -171,3 +160,3 @@ /// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else. | ||
| 0 => true, | ||
| -1 => last_os_error().raw_os_error() == Some(libc::EAGAIN), | ||
| -1 => utils::get_errno() == libc::EAGAIN, | ||
| _ => false, | ||
@@ -214,3 +203,3 @@ } | ||
| pub(super) fn wait_until_rng_ready() -> Result<(), Error> { | ||
| let fd = open_readonly(b"/dev/random\0")?; | ||
| let fd = open_readonly(c"/dev/random")?; | ||
| let mut pfd = libc::pollfd { | ||
@@ -230,8 +219,8 @@ fd, | ||
| } | ||
| let err = last_os_error(); | ||
| let errno = utils::get_errno(); | ||
| // Assuming that `poll` is called correctly, | ||
| // on Linux it can return only EINTR and ENOMEM errors. | ||
| match err.raw_os_error() { | ||
| Some(libc::EINTR) => continue, | ||
| _ => break Err(err), | ||
| match errno { | ||
| libc::EINTR => continue, | ||
| _ => break Err(Error::from_errno(errno)), | ||
| } | ||
@@ -238,0 +227,0 @@ }; |
@@ -9,5 +9,2 @@ //! Implementation for VxWorks | ||
| #[path = "../util_libc.rs"] | ||
| mod util_libc; | ||
| pub use crate::util::{inner_u32, inner_u64}; | ||
@@ -46,3 +43,4 @@ | ||
| if ret != 0 { | ||
| return Err(util_libc::last_os_error()); | ||
| let errno = unsafe { libc::errnoGet() }; | ||
| return Err(Error::from_errno(errno)); | ||
| } | ||
@@ -49,0 +47,0 @@ } |
@@ -10,3 +10,3 @@ //! Implementation for WASI Preview 1 | ||
| #[link(wasm_import_module = "wasi_snapshot_preview1")] | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| fn random_get(arg0: i32, arg1: i32) -> i32; | ||
@@ -13,0 +13,0 @@ } |
@@ -59,3 +59,3 @@ //! Implementation for WASM based on Web and Node.js | ||
| #[wasm_bindgen] | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| // Crypto.getRandomValues() | ||
@@ -62,0 +62,0 @@ #[cfg(not(target_feature = "atomics"))] |
@@ -23,3 +23,3 @@ //! Legacy implementation for Windows XP and later | ||
| #[link(name = "advapi32")] | ||
| extern "system" { | ||
| unsafe extern "system" { | ||
| #[link_name = "SystemFunction036"] | ||
@@ -26,0 +26,0 @@ fn RtlGenRandom(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN; |
@@ -29,5 +29,3 @@ //! Implementation for Windows 10 and later | ||
| // Binding to the Windows.Win32.Security.Cryptography.ProcessPrng API. As | ||
| // bcryptprimitives.dll lacks an import library, we use "raw-dylib". This | ||
| // was added in Rust 1.65 for x86_64/aarch64 and in Rust 1.71 for x86. | ||
| // We don't need MSRV 1.71, as we only use this backend on Rust 1.78 and later. | ||
| // bcryptprimitives.dll lacks an import library, we use "raw-dylib". | ||
| #[cfg_attr( | ||
@@ -45,7 +43,7 @@ target_arch = "x86", | ||
| )] | ||
| extern "system" { | ||
| unsafe extern "system" { | ||
| fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; | ||
| } | ||
| #[allow(clippy::upper_case_acronyms, clippy::incompatible_msrv)] | ||
| type BOOL = core::ffi::c_int; // MSRV 1.64, similarly OK for this backend. | ||
| #[expect(clippy::upper_case_acronyms)] | ||
| type BOOL = core::ffi::c_int; | ||
| const TRUE: BOOL = 1; | ||
@@ -56,9 +54,7 @@ | ||
| let result = unsafe { ProcessPrng(dest.as_mut_ptr().cast::<u8>(), dest.len()) }; | ||
| // Since Windows 10, calls to the user-mode RNG are guaranteed to never | ||
| // fail during runtime (rare windows W); `ProcessPrng` will only ever | ||
| // return 1 (which is how windows represents TRUE). | ||
| // See the bottom of page 6 of the aforementioned Windows RNG | ||
| // whitepaper for more information. | ||
| // `ProcessPrng` is documented to always return TRUE. All potential errors are handled | ||
| // during loading of `BCryptPrimitive.dll`. See the "Process base PRNG" section | ||
| // in the aforementioned Windows RNG whitepaper for more information. | ||
| debug_assert!(result == TRUE); | ||
| Ok(()) | ||
| } |
@@ -10,7 +10,5 @@ extern crate std; | ||
| Some(errno) => io::Error::from_raw_os_error(errno), | ||
| None => io::Error::new(io::ErrorKind::Other, err), | ||
| None => io::Error::other(err), | ||
| } | ||
| } | ||
| } | ||
| impl std::error::Error for Error {} |
+34
-5
@@ -6,4 +6,2 @@ #[cfg(feature = "std")] | ||
| // This private alias mirrors `std::io::RawOsError`: | ||
| // https://doc.rust-lang.org/std/io/type.RawOsError.html) | ||
| cfg_if::cfg_if!( | ||
@@ -13,7 +11,18 @@ if #[cfg(target_os = "uefi")] { | ||
| // https://uefi.org/specs/UEFI/2.10/Apx_D_Status_Codes.html | ||
| type RawOsError = usize; | ||
| /// Raw error code. | ||
| /// | ||
| /// This alias mirrors unstable [`std::io::RawOsError`]. | ||
| /// | ||
| /// [`std::io::RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html | ||
| pub type RawOsError = usize; | ||
| type NonZeroRawOsError = core::num::NonZeroUsize; | ||
| const UEFI_ERROR_FLAG: RawOsError = 1 << (RawOsError::BITS - 1); | ||
| } else { | ||
| type RawOsError = i32; | ||
| /// Raw error code. | ||
| /// | ||
| /// This alias mirrors unstable [`std::io::RawOsError`]. | ||
| /// | ||
| /// [`std::io::RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html | ||
| pub type RawOsError = i32; | ||
| type NonZeroRawOsError = core::num::NonZeroI32; | ||
@@ -53,5 +62,23 @@ } | ||
| /// Creates a new instance of an `Error` from a negative error code. | ||
| /// Creates a new `Error` instance from a positive error code. | ||
| /// | ||
| /// Returns [`Error::ERRNO_NOT_POSITIVE`] for zero and negative error codes. | ||
| #[cfg(not(target_os = "uefi"))] | ||
| #[allow(dead_code)] | ||
| pub(super) fn from_errno(errno: i32) -> Self { | ||
| if errno > 0 { | ||
| let code = errno | ||
| .checked_neg() | ||
| .expect("Positive number can be always negated"); | ||
| Error::from_neg_error_code(code) | ||
| } else { | ||
| Error::ERRNO_NOT_POSITIVE | ||
| } | ||
| } | ||
| /// Creates a new `Error` instance from a negative error code. | ||
| /// | ||
| /// Returns [`Error::UNEXPECTED`] for zero and positive error codes. | ||
| #[cfg(not(target_os = "uefi"))] | ||
| #[allow(dead_code)] | ||
| pub(super) fn from_neg_error_code(code: RawOsError) -> Self { | ||
@@ -182,2 +209,4 @@ if code < 0 { | ||
| impl core::error::Error for Error {} | ||
| impl fmt::Debug for Error { | ||
@@ -184,0 +213,0 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
+11
-2
@@ -42,4 +42,13 @@ // Overwrite links to crate items with intra-crate links | ||
| pub use crate::error::Error; | ||
| /// `rand_core` adapter | ||
| #[cfg(feature = "sys_rng")] | ||
| mod sys_rng; | ||
| #[cfg(feature = "sys_rng")] | ||
| pub use rand_core; | ||
| #[cfg(feature = "sys_rng")] | ||
| pub use sys_rng::SysRng; | ||
| pub use crate::error::{Error, RawOsError}; | ||
| /// Fill `dest` with random bytes from the system's preferred random number source. | ||
@@ -104,3 +113,3 @@ /// | ||
| #[cfg(getrandom_msan)] | ||
| extern "C" { | ||
| unsafe extern "C" { | ||
| fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); | ||
@@ -107,0 +116,0 @@ } |
+3
-15
@@ -9,5 +9,4 @@ #![allow(dead_code)] | ||
| #[inline(always)] | ||
| #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. | ||
| pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] { | ||
| let ptr = ptr_from_mut::<[MaybeUninit<T>]>(slice) as *mut [T]; | ||
| let ptr = ptr::from_mut(slice) as *mut [T]; | ||
| // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. | ||
@@ -25,3 +24,3 @@ unsafe { &mut *ptr } | ||
| pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] { | ||
| let ptr = ptr_from_ref::<[T]>(slice) as *const [MaybeUninit<T>]; | ||
| let ptr = ptr::from_ref(slice) as *const [MaybeUninit<T>]; | ||
| // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. | ||
@@ -36,5 +35,4 @@ unsafe { &*ptr } | ||
| #[inline(always)] | ||
| #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. | ||
| pub unsafe fn slice_as_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] { | ||
| let ptr = ptr_from_mut::<[T]>(slice) as *mut [MaybeUninit<T>]; | ||
| let ptr = ptr::from_mut(slice) as *mut [MaybeUninit<T>]; | ||
| // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. | ||
@@ -44,12 +42,2 @@ unsafe { &mut *ptr } | ||
| // TODO: MSRV(1.76.0): Replace with `core::ptr::from_mut`. | ||
| fn ptr_from_mut<T: ?Sized>(r: &mut T) -> *mut T { | ||
| r | ||
| } | ||
| // TODO: MSRV(1.76.0): Replace with `core::ptr::from_ref`. | ||
| fn ptr_from_ref<T: ?Sized>(r: &T) -> *const T { | ||
| r | ||
| } | ||
| /// Default implementation of `inner_u32` on top of `fill_uninit` | ||
@@ -56,0 +44,0 @@ #[inline] |
+9
-14
@@ -43,8 +43,2 @@ use core::mem::MaybeUninit; | ||
| // TODO: use `[const { MaybeUninit::uninit() }; N]` after MSRV is bumped to 1.79+ | ||
| // or `MaybeUninit::uninit_array` | ||
| fn uninit_vec(n: usize) -> Vec<MaybeUninit<u8>> { | ||
| vec![MaybeUninit::uninit(); n] | ||
| } | ||
| // Tests the quality of calling getrandom on two large buffers | ||
@@ -59,4 +53,4 @@ #[test] | ||
| let mut t1 = uninit_vec(N); | ||
| let mut t2 = uninit_vec(N); | ||
| let mut t1 = [MaybeUninit::uninit(); N]; | ||
| let mut t2 = [MaybeUninit::uninit(); N]; | ||
| let r1 = fill_uninit(&mut t1).unwrap(); | ||
@@ -153,4 +147,4 @@ let r2 = fill_uninit(&mut t2).unwrap(); | ||
| while num_bytes < 256 { | ||
| let mut buf1 = uninit_vec(N); | ||
| let mut buf2 = uninit_vec(N); | ||
| let mut buf1 = [MaybeUninit::uninit(); N]; | ||
| let mut buf2 = [MaybeUninit::uninit(); N]; | ||
@@ -182,3 +176,3 @@ let s1 = &mut buf1[..size]; | ||
| const N: usize = 100_000; | ||
| let mut huge = uninit_vec(N); | ||
| let mut huge = [MaybeUninit::uninit(); N]; | ||
| let res = fill_uninit(&mut huge).unwrap(); | ||
@@ -267,3 +261,4 @@ assert_eq!(res.len(), N); | ||
| // WARNING: this custom implementation is for testing purposes ONLY! | ||
| #[no_mangle] | ||
| #[unsafe(no_mangle)] | ||
| unsafe extern "Rust" fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error> { | ||
@@ -283,3 +278,3 @@ use std::time::{SystemTime, UNIX_EPOCH}; | ||
| let val = rng.next_u32(); | ||
| core::ptr::write_unaligned(dest_u32.add(i), val); | ||
| unsafe { core::ptr::write_unaligned(dest_u32.add(i), val) }; | ||
| } | ||
@@ -290,3 +285,3 @@ if len % 4 != 0 { | ||
| let val = rng.next_u32(); | ||
| core::ptr::write_unaligned(dest.add(i), val as u8); | ||
| unsafe { core::ptr::write_unaligned(dest.add(i), val as u8) }; | ||
| } | ||
@@ -293,0 +288,0 @@ } |
| use core::mem::MaybeUninit; | ||
| /// Unpoisons `buf` if MSAN support is enabled. | ||
| /// | ||
| /// Most backends do not need to unpoison their output. Rust language- and | ||
| /// library- provided functionality unpoisons automatically. Similarly, libc | ||
| /// either natively supports MSAN and/or MSAN hooks libc-provided functions | ||
| /// to unpoison outputs on success. Only when all of these things are | ||
| /// bypassed do we need to do it ourselves. | ||
| /// | ||
| /// The call to unpoison should be done as close to the write as possible. | ||
| /// For example, if the backend partially fills the output buffer in chunks, | ||
| /// each chunk should be unpoisoned individually. This way, the correctness of | ||
| /// the chunking logic can be validated (in part) using MSAN. | ||
| pub unsafe fn unpoison(buf: &mut [MaybeUninit<u8>]) { | ||
| cfg_if! { | ||
| if #[cfg(getrandom_msan)] { | ||
| extern "C" { | ||
| fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); | ||
| } | ||
| let a = buf.as_mut_ptr().cast(); | ||
| let size = buf.len(); | ||
| #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. | ||
| unsafe { | ||
| __msan_unpoison(a, size); | ||
| } | ||
| } else { | ||
| let _ = buf; | ||
| } | ||
| } | ||
| } | ||
| /// Interprets the result of the `getrandom` syscall of Linux, unpoisoning any | ||
| /// written part of `buf`. | ||
| /// | ||
| /// `buf` must be the output buffer that was originally passed to the `getrandom` | ||
| /// syscall. | ||
| /// | ||
| /// `ret` must be the result returned by `getrandom`. If `ret` is negative or | ||
| /// larger than the length of `buf` then nothing is done. | ||
| /// | ||
| /// Memory Sanitizer only intercepts `getrandom` on this condition (from its | ||
| /// source code): | ||
| /// ```c | ||
| /// #define SANITIZER_INTERCEPT_GETRANDOM \ | ||
| /// ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD || SI_SOLARIS) | ||
| /// ``` | ||
| /// So, effectively, we have to assume that it is never intercepted on Linux. | ||
| #[cfg(any(target_os = "android", target_os = "linux"))] | ||
| pub unsafe fn unpoison_linux_getrandom_result(buf: &mut [MaybeUninit<u8>], ret: isize) { | ||
| if let Ok(bytes_written) = usize::try_from(ret) { | ||
| if let Some(written) = buf.get_mut(..bytes_written) { | ||
| #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. | ||
| unsafe { | ||
| unpoison(written) | ||
| } | ||
| } | ||
| } | ||
| } |
-64
| //! Helpers built around pointer-sized atomics. | ||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| // This structure represents a lazily initialized static usize value. Useful | ||
| // when it is preferable to just rerun initialization instead of locking. | ||
| // unsync_init will invoke an init() function until it succeeds, then return the | ||
| // cached value for future calls. | ||
| // | ||
| // unsync_init supports init() "failing". If the init() method returns UNINIT, | ||
| // that value will be returned as normal, but will not be cached. | ||
| // | ||
| // Users should only depend on the _value_ returned by init() functions. | ||
| // Specifically, for the following init() function: | ||
| // fn init() -> usize { | ||
| // a(); | ||
| // let v = b(); | ||
| // c(); | ||
| // v | ||
| // } | ||
| // the effects of c() or writes to shared memory will not necessarily be | ||
| // observed and additional synchronization methods may be needed. | ||
| struct LazyUsize(AtomicUsize); | ||
| impl LazyUsize { | ||
| // The initialization is not completed. | ||
| const UNINIT: usize = usize::MAX; | ||
| const fn new() -> Self { | ||
| Self(AtomicUsize::new(Self::UNINIT)) | ||
| } | ||
| // Runs the init() function at most once, returning the value of some run of | ||
| // init(). Multiple callers can run their init() functions in parallel. | ||
| // init() should always return the same value, if it succeeds. | ||
| fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { | ||
| #[cold] | ||
| fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize { | ||
| let val = init(); | ||
| this.0.store(val, Ordering::Relaxed); | ||
| val | ||
| } | ||
| // Relaxed ordering is fine, as we only have a single atomic variable. | ||
| let val = self.0.load(Ordering::Relaxed); | ||
| if val != Self::UNINIT { | ||
| val | ||
| } else { | ||
| do_init(self, init) | ||
| } | ||
| } | ||
| } | ||
| // Identical to LazyUsize except with bool instead of usize. | ||
| pub(crate) struct LazyBool(LazyUsize); | ||
| impl LazyBool { | ||
| pub const fn new() -> Self { | ||
| Self(LazyUsize::new()) | ||
| } | ||
| pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { | ||
| self.0.unsync_init(|| usize::from(init())) != 0 | ||
| } | ||
| } |
| use crate::Error; | ||
| use core::mem::MaybeUninit; | ||
| cfg_if! { | ||
| if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] { | ||
| use libc::__errno as errno_location; | ||
| } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] { | ||
| use libc::__errno_location as errno_location; | ||
| } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { | ||
| use libc::___errno as errno_location; | ||
| } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] { | ||
| use libc::__error as errno_location; | ||
| } else if #[cfg(target_os = "haiku")] { | ||
| use libc::_errnop as errno_location; | ||
| } else if #[cfg(target_os = "nto")] { | ||
| use libc::__get_errno_ptr as errno_location; | ||
| } else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] { | ||
| extern "C" { | ||
| // Not provided by libc: https://github.com/rust-lang/libc/issues/1995 | ||
| fn __errno() -> *mut libc::c_int; | ||
| } | ||
| use __errno as errno_location; | ||
| } else if #[cfg(target_os = "aix")] { | ||
| use libc::_Errno as errno_location; | ||
| } | ||
| } | ||
| cfg_if! { | ||
| if #[cfg(target_os = "vxworks")] { | ||
| use libc::errnoGet as get_errno; | ||
| } else { | ||
| unsafe fn get_errno() -> libc::c_int { *errno_location() } | ||
| } | ||
| } | ||
| pub(crate) fn last_os_error() -> Error { | ||
| // We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32` | ||
| let errno: i32 = unsafe { get_errno() }; | ||
| if errno > 0 { | ||
| let code = errno | ||
| .checked_neg() | ||
| .expect("Positive number can be always negated"); | ||
| Error::from_neg_error_code(code) | ||
| } else { | ||
| Error::ERRNO_NOT_POSITIVE | ||
| } | ||
| } | ||
| /// Fill a buffer by repeatedly invoking `sys_fill`. | ||
| /// | ||
| /// The `sys_fill` function: | ||
| /// - should return -1 and set errno on failure | ||
| /// - should return the number of bytes written on success | ||
| #[allow(dead_code)] | ||
| pub(crate) fn sys_fill_exact( | ||
| mut buf: &mut [MaybeUninit<u8>], | ||
| sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t, | ||
| ) -> Result<(), Error> { | ||
| while !buf.is_empty() { | ||
| let res = sys_fill(buf); | ||
| match res { | ||
| res if res > 0 => { | ||
| let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?; | ||
| buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?; | ||
| } | ||
| -1 => { | ||
| let err = last_os_error(); | ||
| // We should try again if the call was interrupted. | ||
| if err.raw_os_error() != Some(libc::EINTR) { | ||
| return Err(err); | ||
| } | ||
| } | ||
| // Negative return codes not equal to -1 should be impossible. | ||
| // EOF (ret = 0) should be impossible, as the data we are reading | ||
| // should be an infinite stream of random bytes. | ||
| _ => return Err(Error::UNEXPECTED), | ||
| } | ||
| } | ||
| Ok(()) | ||
| } |
Sorry, the diff of this file is not supported yet