4 pub fn hashmap_random_keys() -> (u64, u64) {
7 let view
= slice
::from_raw_parts_mut(&mut v
as *mut _
as *mut u8, mem
::size_of_val(&v
));
15 not(target_os
= "macos"),
16 not(target_os
= "ios"),
17 not(target_os
= "openbsd"),
18 not(target_os
= "freebsd"),
19 not(target_os
= "netbsd"),
20 not(target_os
= "fuchsia"),
21 not(target_os
= "redox")
27 #[cfg(any(target_os = "linux", target_os = "android"))]
28 fn getrandom(buf
: &mut [u8]) -> libc
::c_long
{
30 libc
::syscall(libc
::SYS_getrandom
, buf
.as_mut_ptr(), buf
.len(), libc
::GRND_NONBLOCK
)
34 #[cfg(not(any(target_os = "linux", target_os = "android")))]
35 fn getrandom_fill_bytes(_buf
: &mut [u8]) -> bool
{
39 #[cfg(any(target_os = "linux", target_os = "android"))]
40 fn getrandom_fill_bytes(v
: &mut [u8]) -> bool
{
41 use crate::sync
::atomic
::{AtomicBool, Ordering}
;
42 use crate::sys
::os
::errno
;
44 static GETRANDOM_UNAVAILABLE
: AtomicBool
= AtomicBool
::new(false);
45 if GETRANDOM_UNAVAILABLE
.load(Ordering
::Relaxed
) {
50 while read
< v
.len() {
51 let result
= getrandom(&mut v
[read
..]);
53 let err
= errno() as libc
::c_int
;
54 if err
== libc
::EINTR
{
56 } else if err
== libc
::ENOSYS
|| err
== libc
::EPERM
{
57 // Fall back to reading /dev/urandom if `getrandom` is not
58 // supported on the current kernel.
60 // Also fall back in case it is disabled by something like
61 // seccomp or inside of virtual machines.
62 GETRANDOM_UNAVAILABLE
.store(true, Ordering
::Relaxed
);
64 } else if err
== libc
::EAGAIN
{
67 panic
!("unexpected getrandom error: {}", err
);
70 read
+= result
as usize;
76 pub fn fill_bytes(v
: &mut [u8]) {
77 // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
78 // meaning it would have blocked because the non-blocking pool (urandom)
79 // has not initialized in the kernel yet due to a lack of entropy. The
80 // fallback we do here is to avoid blocking applications which could
81 // depend on this call without ever knowing they do and don't have a
82 // work around. The PRNG of /dev/urandom will still be used but over a
83 // possibly predictable entropy pool.
84 if getrandom_fill_bytes(v
) {
88 // getrandom failed because it is permanently or temporarily (because
89 // of missing entropy) unavailable. Open /dev/urandom, read from it,
90 // and close it again.
91 let mut file
= File
::open("/dev/urandom").expect("failed to open /dev/urandom");
92 file
.read_exact(v
).expect("failed to read /dev/urandom")
96 #[cfg(target_os = "macos")]
100 use crate::sys
::os
::errno
;
101 use libc
::{c_int, c_void, size_t}
;
103 fn getentropy_fill_bytes(v
: &mut [u8]) -> bool
{
104 weak
!(fn getentropy(*mut c_void
, size_t
) -> c_int
);
109 // getentropy(2) permits a maximum buffer size of 256 bytes
110 for s
in v
.chunks_mut(256) {
111 let ret
= unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) }
;
113 panic
!("unexpected getentropy error: {}", errno());
121 pub fn fill_bytes(v
: &mut [u8]) {
122 if getentropy_fill_bytes(v
) {
126 // for older macos which doesn't support getentropy
127 let mut file
= File
::open("/dev/urandom").expect("failed to open /dev/urandom");
128 file
.read_exact(v
).expect("failed to read /dev/urandom")
132 #[cfg(target_os = "openbsd")]
134 use crate::sys
::os
::errno
;
136 pub fn fill_bytes(v
: &mut [u8]) {
137 // getentropy(2) permits a maximum buffer size of 256 bytes
138 for s
in v
.chunks_mut(256) {
139 let ret
= unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) }
;
141 panic
!("unexpected getentropy error: {}", errno());
147 // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
148 // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
149 // from `/dev/random` and which runs on its own thread accessed via GCD.
150 // This seems needlessly heavyweight for the purposes of generating two u64s
151 // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
152 // only used on iOS where direct access to `/dev/urandom` is blocked by the
154 #[cfg(target_os = "ios")]
158 use libc
::{c_int, size_t}
;
162 #[allow(non_upper_case_globals)]
163 const kSecRandomDefault
: *const SecRandom
= ptr
::null();
166 fn SecRandomCopyBytes(rnd
: *const SecRandom
, count
: size_t
, bytes
: *mut u8) -> c_int
;
169 pub fn fill_bytes(v
: &mut [u8]) {
170 let ret
= unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) }
;
172 panic
!("couldn't generate random bytes: {}", io
::Error
::last_os_error());
177 #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
181 pub fn fill_bytes(v
: &mut [u8]) {
182 let mib
= [libc
::CTL_KERN
, libc
::KERN_ARND
];
183 // kern.arandom permits a maximum buffer size of 256 bytes
184 for s
in v
.chunks_mut(256) {
185 let mut s_len
= s
.len();
189 mib
.len() as libc
::c_uint
,
190 s
.as_mut_ptr() as *mut _
,
196 if ret
== -1 || s_len
!= s
.len() {
198 "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
208 #[cfg(target_os = "fuchsia")]
210 #[link(name = "zircon")]
212 fn zx_cprng_draw(buffer
: *mut u8, len
: usize);
215 pub fn fill_bytes(v
: &mut [u8]) {
216 unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
220 #[cfg(target_os = "redox")]
225 pub fn fill_bytes(v
: &mut [u8]) {
226 // Open rand:, read from it, and close it again.
227 let mut file
= File
::open("rand:").expect("failed to open rand:");
228 file
.read_exact(v
).expect("failed to read rand:")