1111use core:: cell:: UnsafeCell ;
1212use std:: rc:: Rc ;
1313use std:: thread_local;
14+ use std:: fmt;
1415
1516use super :: std:: Core ;
1617use crate :: rngs:: adapter:: ReseedingRng ;
@@ -39,31 +40,43 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
3940
4041/// A reference to the thread-local generator
4142///
43+ /// This type is a reference to a lazily-initialized thread-local generator.
4244/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
4345/// This handle is safe to use everywhere (including thread-local destructors),
4446/// though it is recommended not to use inside a fork handler.
4547/// The handle cannot be passed between threads (is not `Send` or `Sync`).
4648///
47- /// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
48- /// and is automatically seeded from [`OsRng`].
49+ /// `ThreadRng` uses the same CSPRNG as [`StdRng`], ChaCha12. As with
50+ /// [`StdRng`], the algorithm may be changed, subject to reasonable expectations
51+ /// of security and performance.
4952///
50- /// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
51- /// the PRNG from fresh entropy every 64 kiB of random data as well as after a
52- /// fork on Unix (though not quite immediately; see documentation of
53- /// [`ReseedingRng`]).
54- /// Note that the reseeding is done as an extra precaution against side-channel
55- /// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
56- /// The PRNG algorithms used are assumed to be secure.
53+ /// `ThreadRng` is automatically seeded from [`OsRng`] with periodic reseeding
54+ /// (every 64 kiB, as well as "soon" after a fork on Unix — see [`ReseedingRng`]
55+ /// documentation for details).
56+ ///
57+ /// Security must be considered relative to a thread model and validation
58+ /// requirements. `ThreadRng` attempts to meet basic security considerations
59+ /// for producing unpredictable random numbers: use a CSPRNG, use a
60+ /// recommended platform-specific seed ([`OsRng`]), and avoid
61+ /// leaking internal secrets e.g. via [`Debug`] implementation or serialization.
62+ /// Memory is not zeroized on drop.
5763///
5864/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
5965/// [`StdRng`]: crate::rngs::StdRng
6066#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
61- #[ derive( Clone , Debug ) ]
67+ #[ derive( Clone ) ]
6268pub struct ThreadRng {
6369 // Rc is explicitly !Send and !Sync
6470 rng : Rc < UnsafeCell < ReseedingRng < Core , OsRng > > > ,
6571}
6672
73+ /// Debug implementation does not leak internal state
74+ impl fmt:: Debug for ThreadRng {
75+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
76+ write ! ( fmt, "ThreadRng {{ .. }}" )
77+ }
78+ }
79+
6780thread_local ! (
6881 // We require Rc<..> to avoid premature freeing when thread_rng is used
6982 // within thread-local destructors. See #968.
@@ -77,13 +90,23 @@ thread_local!(
7790 }
7891) ;
7992
80- /// Retrieve the lazily-initialized thread-local random number generator,
81- /// seeded by the system. Intended to be used in method chaining style,
82- /// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
83- /// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making
84- /// `ThreadRng::default()` equivalent.
93+ /// Access the thread-local generator
94+ ///
95+ /// Returns a reference to the local [`ThreadRng`], initializing the generator
96+ /// on the first call on each thread.
8597///
86- /// For more information see [`ThreadRng`].
98+ /// Example usage:
99+ /// ```
100+ /// use rand::Rng;
101+ ///
102+ /// # fn main() {
103+ /// // rand::random() may be used instead of rand::thread_rng().gen():
104+ /// println!("A random boolean: {}", rand::random::<bool>());
105+ ///
106+ /// let mut rng = rand::thread_rng();
107+ /// println!("A simulated die roll: {}", rng.gen_range(1..=6));
108+ /// # }
109+ /// ```
87110#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
88111pub fn thread_rng ( ) -> ThreadRng {
89112 let rng = THREAD_RNG_KEY . with ( |t| t. clone ( ) ) ;
@@ -92,7 +115,7 @@ pub fn thread_rng() -> ThreadRng {
92115
93116impl Default for ThreadRng {
94117 fn default ( ) -> ThreadRng {
95- crate :: prelude :: thread_rng ( )
118+ thread_rng ( )
96119 }
97120}
98121
@@ -140,4 +163,11 @@ mod test {
140163 r. gen :: < i32 > ( ) ;
141164 assert_eq ! ( r. gen_range( 0 ..1 ) , 0 ) ;
142165 }
166+
167+ #[ test]
168+ fn test_debug_output ( ) {
169+ // We don't care about the exact output here, but it must not include
170+ // private CSPRNG state or the cache stored by BlockRng!
171+ assert_eq ! ( std:: format!( "{:?}" , crate :: thread_rng( ) ) , "ThreadRng { .. }" ) ;
172+ }
143173}
0 commit comments