diff options
| author | bors <bors@rust-lang.org> | 2017-11-09 18:14:48 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-11-09 18:14:48 +0000 |
| commit | f1ea23e2cc72cafad1dc25a06c09ec2de8e323eb (patch) | |
| tree | 4bafb2a94c6755051649f9e6cfca17c0312712ab /src/libstd/sys/unix/rand.rs | |
| parent | 98e791e7e135ef6526ca97c33fcf8cd0db50320f (diff) | |
| parent | 5c3fe111d4a6e72f0461320f5166bcd6aaf2f37f (diff) | |
| download | rust-f1ea23e2cc72cafad1dc25a06c09ec2de8e323eb.tar.gz rust-f1ea23e2cc72cafad1dc25a06c09ec2de8e323eb.zip | |
Auto merge of #45725 - alexcrichton:std-less-rand, r=dtolnay
Working towards a libc-less (wasm32) libstd This is a series of commits I was able to extract from prepare to comiple libstd on a "bare libc-less" target, notably wasm32. The actual wasm32 bits I intend to send in a PR later, this is just some internal refactorings required for libstd to work with a `libc` that's empty and a few other assorted refactorings. No functional change should be included in this PR for users of libstd, this is intended to just be internal refactorings.
Diffstat (limited to 'src/libstd/sys/unix/rand.rs')
| -rw-r--r-- | src/libstd/sys/unix/rand.rs | 289 |
1 files changed, 74 insertions, 215 deletions
diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index e2d40742c71..bbffe0f0ffe 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -8,20 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::imp::OsRng; - use mem; - -fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 { - let mut buf: [u8; 4] = [0; 4]; - fill_buf(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } -} - -fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 { - let mut buf: [u8; 8] = [0; 8]; - fill_buf(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } +use slice; + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut v = (0, 0); + unsafe { + let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, + mem::size_of_val(&v)); + imp::fill_bytes(view); + } + return v } #[cfg(all(unix, @@ -30,14 +27,9 @@ fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 { not(target_os = "freebsd"), not(target_os = "fuchsia")))] mod imp { - use self::OsRngInner::*; - use super::{next_u32, next_u64}; - use fs::File; - use io; + use io::Read; use libc; - use rand::Rng; - use rand::reader::ReaderRng; use sys::os::errno; #[cfg(all(target_os = "linux", @@ -81,7 +73,7 @@ mod imp { target_arch = "s390x"))))] fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } - fn getrandom_fill_bytes(v: &mut [u8]) { + fn getrandom_fill_bytes(v: &mut [u8]) -> bool { let mut read = 0; while read < v.len() { let result = getrandom(&mut v[read..]); @@ -90,18 +82,7 @@ mod imp { if err == libc::EINTR { continue; } else if err == libc::EAGAIN { - // if getrandom() returns EAGAIN it would have blocked - // because the non-blocking pool (urandom) has not - // initialized in the kernel yet due to a lack of entropy - // the fallback we do here is to avoid blocking applications - // which could depend on this call without ever knowing - // they do and don't have a work around. The PRNG of - // /dev/urandom will still be used but not over a completely - // full entropy pool - let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom"); - let mut reader_rng = ReaderRng::new(reader); - reader_rng.fill_bytes(&mut v[read..]); - read += v.len(); + return false } else { panic!("unexpected getrandom error: {}", err); } @@ -109,6 +90,8 @@ mod imp { read += result as usize; } } + + return true } #[cfg(all(target_os = "linux", @@ -120,6 +103,7 @@ mod imp { target_arch = "powerpc64", target_arch = "s390x")))] fn is_getrandom_available() -> bool { + use io; use sync::atomic::{AtomicBool, Ordering}; use sync::Once; @@ -151,89 +135,37 @@ mod imp { target_arch = "s390x"))))] fn is_getrandom_available() -> bool { false } - pub struct OsRng { - inner: OsRngInner, - } - - enum OsRngInner { - OsGetrandomRng, - OsReaderRng(ReaderRng<File>), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - if is_getrandom_available() { - return Ok(OsRng { inner: OsGetrandomRng }); - } - - let reader = File::open("/dev/urandom")?; - let reader_rng = ReaderRng::new(reader); - - Ok(OsRng { inner: OsReaderRng(reader_rng) }) + pub fn fill_bytes(v: &mut [u8]) { + // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN, + // meaning it would have blocked because the non-blocking pool (urandom) + // has not initialized in the kernel yet due to a lack of entropy the + // fallback we do here is to avoid blocking applications which could + // depend on this call without ever knowing they do and don't have a + // work around. The PRNG of /dev/urandom will still be used but not + // over a completely full entropy pool + if is_getrandom_available() && getrandom_fill_bytes(v) { + return } - } - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - match self.inner { - OsGetrandomRng => next_u32(&mut getrandom_fill_bytes), - OsReaderRng(ref mut rng) => rng.next_u32(), - } - } - fn next_u64(&mut self) -> u64 { - match self.inner { - OsGetrandomRng => next_u64(&mut getrandom_fill_bytes), - OsReaderRng(ref mut rng) => rng.next_u64(), - } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - match self.inner { - OsGetrandomRng => getrandom_fill_bytes(v), - OsReaderRng(ref mut rng) => rng.fill_bytes(v) - } - } + let mut file = File::open("/dev/urandom") + .expect("failed to open /dev/urandom"); + file.read_exact(v).expect("failed to read /dev/urandom"); } } #[cfg(target_os = "openbsd")] mod imp { - use super::{next_u32, next_u64}; - - use io; use libc; use sys::os::errno; - use rand::Rng; - - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, v: &mut [u8]) { - // getentropy(2) permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let ret = unsafe { - libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) - }; - if ret == -1 { - panic!("unexpected getentropy error: {}", errno()); - } + pub fn fill_bytes(v: &mut [u8]) { + // getentropy(2) permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let ret = unsafe { + libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) + }; + if ret == -1 { + panic!("unexpected getentropy error: {}", errno()); } } } @@ -241,18 +173,9 @@ mod imp { #[cfg(target_os = "ios")] mod imp { - use super::{next_u32, next_u64}; - use io; - use ptr; - use rand::Rng; use libc::{c_int, size_t}; - - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } + use ptr; enum SecRandom {} @@ -261,79 +184,41 @@ mod imp { extern { fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, bytes: *mut u8) -> c_int; + count: size_t, + bytes: *mut u8) -> c_int; } - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, v.len(), - v.as_mut_ptr()) - }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } + pub fn fill_bytes(v: &mut [u8]) { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, + v.len(), + v.as_mut_ptr()) + }; + if ret == -1 { + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); } } } #[cfg(target_os = "freebsd")] mod imp { - use super::{next_u32, next_u64}; - - use io; use libc; - use rand::Rng; use ptr; - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let mib = [libc::CTL_KERN, libc::KERN_ARND]; - // kern.arandom permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let mut s_len = s.len(); - let ret = unsafe { - libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, - s.as_mut_ptr() as *mut _, &mut s_len, - ptr::null(), 0) - }; - if ret == -1 || s_len != s.len() { - panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", - ret, s.len(), s_len); - } + pub fn fill_bytes(v: &mut [u8]) { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + // kern.arandom permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let mut s_len = s.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + s.as_mut_ptr() as *mut _, &mut s_len, + ptr::null(), 0) + }; + if ret == -1 || s_len != s.len() { + panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", + ret, s.len(), s_len); } } } @@ -341,11 +226,6 @@ mod imp { #[cfg(target_os = "fuchsia")] mod imp { - use super::{next_u32, next_u64}; - - use io; - use rand::Rng; - #[link(name = "zircon")] extern { fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; @@ -363,39 +243,18 @@ mod imp { } } - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let mut buf = v; - while !buf.is_empty() { - let ret = getrandom(buf); - match ret { - Err(err) => { - panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", - err, buf.len()) - } - Ok(actual) => { - let move_buf = buf; - buf = &mut move_buf[(actual as usize)..]; - } + pub fn fill_bytes(v: &mut [u8]) { + let mut buf = v; + while !buf.is_empty() { + let ret = getrandom(buf); + match ret { + Err(err) => { + panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", + err, buf.len()) + } + Ok(actual) => { + let move_buf = buf; + buf = &mut move_buf[(actual as usize)..]; } } } |
