99//! Thread-local random number generator
1010
1111use core:: cell:: UnsafeCell ;
12- use core :: ptr :: NonNull ;
12+ use std :: rc :: Rc ;
1313use std:: thread_local;
1414
1515use super :: std:: Core ;
@@ -37,38 +37,42 @@ use crate::{CryptoRng, Error, RngCore, SeedableRng};
3737// of 32 kB and less. We choose 64 kB to avoid significant overhead.
3838const THREAD_RNG_RESEED_THRESHOLD : u64 = 1024 * 64 ;
3939
40- /// The type returned by [`thread_rng`], essentially just a reference to the
41- /// PRNG in thread-local memory.
40+ /// A reference to the thread-local generator
4241///
43- /// `ThreadRng` uses the same PRNG as [`StdRng `] for security and performance .
44- /// As hinted by the name, the generator is thread-local. `ThreadRng` is a
45- /// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
42+ /// An instance can be obtained via [`thread_rng `] or via `ThreadRng::default()` .
43+ /// This handle is safe to use everywhere (including thread-local destructors)
44+ /// but cannot be passed between threads (is not `Send` or `Sync`) .
4645///
47- /// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
48- /// the PRNG from fresh entropy every 64 kiB of random data.
49- /// [`OsRng`] is used to provide seed data.
46+ /// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
47+ /// and is automatically seeded from [`OsRng`].
5048///
49+ /// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
50+ /// the PRNG from fresh entropy every 64 kiB of random data as well as after a
51+ /// fork on Unix (though not quite immediately; see documentation of
52+ /// [`ReseedingRng`]).
5153/// Note that the reseeding is done as an extra precaution against side-channel
5254/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
5355/// The PRNG algorithms used are assumed to be secure.
5456///
5557/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
5658/// [`StdRng`]: crate::rngs::StdRng
5759#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
58- #[ derive( Copy , Clone , Debug ) ]
60+ #[ derive( Clone , Debug ) ]
5961pub struct ThreadRng {
60- // inner raw pointer implies type is neither Send nor Sync
61- rng : NonNull < ReseedingRng < Core , OsRng > > ,
62+ // Rc is explictly ! Send and ! Sync
63+ rng : Rc < UnsafeCell < ReseedingRng < Core , OsRng > > > ,
6264}
6365
6466thread_local ! (
65- static THREAD_RNG_KEY : UnsafeCell <ReseedingRng <Core , OsRng >> = {
67+ // We require Rc<..> to avoid premature freeing when thread_rng is used
68+ // within thread-local destructors. See #968.
69+ static THREAD_RNG_KEY : Rc <UnsafeCell <ReseedingRng <Core , OsRng >>> = {
6670 let r = Core :: from_rng( OsRng ) . unwrap_or_else( |err|
6771 panic!( "could not initialize thread_rng: {}" , err) ) ;
6872 let rng = ReseedingRng :: new( r,
6973 THREAD_RNG_RESEED_THRESHOLD ,
7074 OsRng ) ;
71- UnsafeCell :: new( rng)
75+ Rc :: new ( UnsafeCell :: new( rng) )
7276 }
7377) ;
7478
@@ -81,9 +85,8 @@ thread_local!(
8185/// For more information see [`ThreadRng`].
8286#[ cfg_attr( doc_cfg, doc( cfg( all( feature = "std" , feature = "std_rng" ) ) ) ) ]
8387pub fn thread_rng ( ) -> ThreadRng {
84- let raw = THREAD_RNG_KEY . with ( |t| t. get ( ) ) ;
85- let nn = NonNull :: new ( raw) . unwrap ( ) ;
86- ThreadRng { rng : nn }
88+ let rng = THREAD_RNG_KEY . with ( |t| t. clone ( ) ) ;
89+ ThreadRng { rng }
8790}
8891
8992impl Default for ThreadRng {
@@ -92,23 +95,30 @@ impl Default for ThreadRng {
9295 }
9396}
9497
98+ impl ThreadRng {
99+ #[ inline( always) ]
100+ fn rng ( & mut self ) -> & mut ReseedingRng < Core , OsRng > {
101+ unsafe { & mut * self . rng . get ( ) }
102+ }
103+ }
104+
95105impl RngCore for ThreadRng {
96106 #[ inline( always) ]
97107 fn next_u32 ( & mut self ) -> u32 {
98- unsafe { self . rng . as_mut ( ) . next_u32 ( ) }
108+ self . rng ( ) . next_u32 ( )
99109 }
100110
101111 #[ inline( always) ]
102112 fn next_u64 ( & mut self ) -> u64 {
103- unsafe { self . rng . as_mut ( ) . next_u64 ( ) }
113+ self . rng ( ) . next_u64 ( )
104114 }
105115
106116 fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
107- unsafe { self . rng . as_mut ( ) . fill_bytes ( dest) }
117+ self . rng ( ) . fill_bytes ( dest)
108118 }
109119
110120 fn try_fill_bytes ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
111- unsafe { self . rng . as_mut ( ) . try_fill_bytes ( dest) }
121+ self . rng ( ) . try_fill_bytes ( dest)
112122 }
113123}
114124
0 commit comments