diff --git a/CHANGELOG.md b/CHANGELOG.md index 57bb3614ff8..3ec7462c963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update. ### Fixes - The `Bernoulli` distribution constructors now reports an error on NaN and on `denominator == 0`. (#925) +- Use `std::sync::Once` to register fork handler, avoiding possible atomicity violation (#928) + +### Changes +- Unix: make libc dependency optional; only use fork protection with std feature (#928) ### Additions - Implement `std::error::Error` for `BernoulliError` (#919) diff --git a/Cargo.toml b/Cargo.toml index e6af38d6344..03d5e35afca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ nightly = ["simd_support"] # enables all features requiring nightly rust serde1 = [] # does nothing, deprecated # Optional dependencies: -std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom"] +std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"] alloc = ["rand_core/alloc"] # enables Vec and Box support (without std) # re-export optional WASM dependencies to avoid breakage: # Warning: wasm-bindgen and stdweb features will be removed in rand 0.8; @@ -68,7 +68,7 @@ features = ["into_bits"] [target.'cfg(unix)'.dependencies] # Used for fork protection (reseeding.rs) -libc = { version = "0.2.22", default-features = false } +libc = { version = "0.2.22", optional = true, default-features = false } # Emscripten does not support 128-bit integers, which are used by ChaCha code. # We work around this by using a different RNG. diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index f7a694f2211..5460e3431f9 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -279,11 +279,10 @@ where } -#[cfg(all(unix, not(target_os = "emscripten")))] +#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))] mod fork { - use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; - #[allow(deprecated)] // Required for compatibility with Rust < 1.24. - use core::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; + use core::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::Once; // Fork protection // @@ -297,16 +296,12 @@ mod fork { // don't update `fork_counter`, so a reseed is attempted as soon as // possible. - #[allow(deprecated)] - static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = AtomicUsize::new(0); pub fn get_fork_counter() -> usize { RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) } - #[allow(deprecated)] - static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT; - extern "C" fn fork_handler() { // Note: fetch_add is defined to wrap on overflow // (which is what we want). @@ -314,14 +309,14 @@ mod fork { } pub fn register_fork_handler() { - if !FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) { - unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) }; - FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed); - } + static REGISTER: Once = Once::new(); + REGISTER.call_once(|| unsafe { + libc::pthread_atfork(None, None, Some(fork_handler)); + }); } } -#[cfg(not(all(unix, not(target_os = "emscripten"))))] +#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))] mod fork { pub fn get_fork_counter() -> usize { 0