Skip to content

Commit 40c49c2

Browse files
committed
ReseedingRng: more robust fork handling
1 parent fcc5baf commit 40c49c2

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

src/rngs/adapter/reseeding.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
2222
///
2323
/// - On a manual call to [`reseed()`].
2424
/// - After `clone()`, the clone will be reseeded on first use.
25-
/// - After a process is forked, the RNG in the child process is reseeded within
26-
/// the next few generated values, depending on the block size of the
27-
/// underlying PRNG. For ChaCha and Hc128 this is a maximum of
28-
/// 15 `u32` values before reseeding.
25+
/// - When a process is forked on UNIX, the RNGs in both the parent and child
26+
/// processes will be reseeded just before the next call to
27+
/// [`BlockRngCore::generate`], i.e. "soon". For ChaCha and Hc128 this is a
28+
/// maximum of fifteen `u32` values before reseeding.
2929
/// - After the PRNG has generated a configurable number of random bytes.
3030
///
3131
/// # When should reseeding after a fixed number of generated bytes be used?
@@ -43,6 +43,12 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
4343
/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
4444
/// after a fixed number of generated bytes.
4545
///
46+
/// # Limitations
47+
///
48+
/// It is recommended that a `ReseedingRng` (including `ThreadRng`) not be used
49+
/// from a fork handler.
50+
/// Use `OsRng` or `getrandom`, or defer your use of the RNG until later.
51+
///
4652
/// # Error handling
4753
///
4854
/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
@@ -310,8 +316,16 @@ mod fork {
310316

311317
pub fn register_fork_handler() {
312318
static REGISTER: Once = Once::new();
313-
REGISTER.call_once(|| unsafe {
314-
libc::pthread_atfork(None, None, Some(fork_handler));
319+
REGISTER.call_once(|| {
320+
// Bump the counter before and after forking (see #1169):
321+
let ret = unsafe { libc::pthread_atfork(
322+
Some(fork_handler),
323+
Some(fork_handler),
324+
Some(fork_handler),
325+
) };
326+
if ret != 0 {
327+
panic!("libc::pthread_atfork failed with code {}", ret);
328+
}
315329
});
316330
}
317331
}

src/rngs/thread.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
4040
/// A reference to the thread-local generator
4141
///
4242
/// 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`).
43+
/// This handle is safe to use everywhere (including thread-local destructors),
44+
/// though it is recommended not to use inside a fork handler.
45+
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
4546
///
4647
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
4748
/// and is automatically seeded from [`OsRng`].

0 commit comments

Comments
 (0)