diff --git a/src/lib.rs b/src/lib.rs index fc2c1c9c7d6..3c7d2cc5149 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,6 +254,7 @@ use std::mem; use std::io; use std::rc::Rc; use std::num::Wrapping as w; +use std::time; pub use os::OsRng; @@ -902,9 +903,9 @@ struct ThreadRngReseeder; impl reseeding::Reseeder for ThreadRngReseeder { fn reseed(&mut self, rng: &mut StdRng) { - *rng = match StdRng::new() { - Ok(r) => r, - Err(e) => panic!("could not reseed thread_rng: {}", e) + match StdRng::new() { + Ok(r) => *rng = r, + Err(_) => rng.reseed(&weak_seed()) } } } @@ -921,8 +922,9 @@ pub struct ThreadRng { /// generator, seeded by the system. Intended to be used in method /// chaining style, e.g. `thread_rng().gen::()`. /// -/// The RNG provided will reseed itself from the operating system -/// after generating a certain amount of randomness. +/// After generating a certain amount of randomness, the RNG will reseed itself +/// from the operating system or, if the operating system RNG returns an error, +/// a seed based on the current system time. /// /// The internal RNG used is platform and architecture dependent, even /// if the operating system random number generator is rigged to give @@ -933,7 +935,7 @@ pub fn thread_rng() -> ThreadRng { thread_local!(static THREAD_RNG_KEY: Rc> = { let r = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("could not initialize thread_rng: {}", e) + Err(_) => StdRng::from_seed(&weak_seed()) }; let rng = reseeding::ReseedingRng::new(r, THREAD_RNG_RESEED_THRESHOLD, @@ -944,6 +946,14 @@ pub fn thread_rng() -> ThreadRng { ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } } +fn weak_seed() -> [usize; 2] { + let now = time::SystemTime::now(); + let unix_time = now.duration_since(time::UNIX_EPOCH).unwrap(); + let seconds = unix_time.as_secs() as usize; + let nanoseconds = unix_time.subsec_nanos() as usize; + [seconds, nanoseconds] +} + impl Rng for ThreadRng { fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32()