Skip to content

Commit 7b2d78d

Browse files
committed
Android/Linux/rdrand: Use once_cell::race::OnceBool instead of LazyBool.
Remove src/lazy.rs. `lazy::LazyBool` had "Last to win the race" semantics; when multiple threads see an uninitialized LazyBool, all of them will calculate a value. As they finish, each one will overwrite the value set by the previous thread. If two threads calculate different values for the boolean, then the value of the boolean can change during the period where the threads are racing. This doesn't seem to be a huge issue with the way it is currently used, but it is hard to reason about. `once_cell::race::OnceBool` has "first to win the race" semantics. When multiple threads see an uninitialized OnceBool, all of them will calculate a vlaue. The first one to finish will write its value; the rest will have their work ignored. Thus there is never any change in the stored value at any point. This is much easier to reason about. The different semantics come down to the fact that once_cell uses `AtomicUsize::compare_exchange` whereas lazy.rs was using `AtomicUsize::store`.
1 parent 267639e commit 7b2d78d

File tree

6 files changed

+17
-76
lines changed

6 files changed

+17
-76
lines changed

Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ exclude = [".*"]
1313

1414
[dependencies]
1515
cfg-if = "1"
16+
once_cell = { version = "1.19.0", default-features = false, optional = true }
17+
18+
[target.'cfg(any(target_os = "android", target_os = "linux", all(target_arch = "x86_64", target_env = "sgx")))'.dependencies]
19+
once_cell = { version = "1.19.0", default-features = false, features = ["race"] }
1620

1721
# When built as part of libstd
1822
compiler_builtins = { version = "0.1", optional = true }
@@ -30,6 +34,10 @@ windows-targets = "0.52"
3034
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
3135
wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
3236
js-sys = { version = "0.3", optional = true }
37+
38+
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dev-dependencies]
39+
once_cell = { version = "1.19.0", default-features = false, features = ["race"] }
40+
3341
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies]
3442
wasm-bindgen-test = "0.3.18"
3543

@@ -40,7 +48,7 @@ std = []
4048
# Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow).
4149
linux_disable_fallback = []
4250
# Feature to enable fallback RDRAND-based implementation on x86/x86_64
43-
rdrand = []
51+
rdrand = ["once_cell/race"]
4452
# Feature to enable JavaScript bindings on wasm*-unknown-unknown
4553
js = ["wasm-bindgen", "js-sys"]
4654
# Feature to enable custom RNG implementations

src/lazy.rs

-66
This file was deleted.

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@ use crate::util::{slice_as_uninit_mut, slice_assume_init_mut};
216216
use core::mem::MaybeUninit;
217217

218218
mod error;
219-
mod lazy;
220219
mod util;
221220
// To prevent a breaking change when targets are added, we always export the
222221
// register_custom_getrandom macro, so old Custom RNG crates continue to build.

src/linux_android_with_fallback.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//! Implementation for Linux / Android with `/dev/urandom` fallback
2-
use crate::{lazy::LazyBool, linux_android, use_file, util_libc::last_os_error, Error};
2+
use crate::{linux_android, use_file, util_libc::last_os_error, Error};
33
use core::mem::MaybeUninit;
4+
use once_cell::race::OnceBool;
45

56
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
67
// getrandom(2) was introduced in Linux 3.17
7-
static HAS_GETRANDOM: LazyBool = LazyBool::new();
8-
if HAS_GETRANDOM.unsync_init(is_getrandom_available) {
8+
static HAS_GETRANDOM: OnceBool = OnceBool::new();
9+
if HAS_GETRANDOM.get_or_init(is_getrandom_available) {
910
linux_android::getrandom_inner(dest)
1011
} else {
1112
use_file::getrandom_inner(dest)

src/rdrand.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! RDRAND backend for x86(-64) targets
2-
use crate::{lazy::LazyBool, util::slice_as_uninit, Error};
2+
use crate::{util::slice_as_uninit, Error};
33
use core::mem::{size_of, MaybeUninit};
4+
use once_cell::race::OnceBool;
45

56
cfg_if! {
67
if #[cfg(target_arch = "x86_64")] {
@@ -94,8 +95,8 @@ fn is_rdrand_good() -> bool {
9495
}
9596

9697
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
97-
static RDRAND_GOOD: LazyBool = LazyBool::new();
98-
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
98+
static RDRAND_GOOD: OnceBool = OnceBool::new();
99+
if !RDRAND_GOOD.get_or_init(is_rdrand_good) {
99100
return Err(Error::NO_RDRAND);
100101
}
101102
// SAFETY: After this point, we know rdrand is supported.

tests/rdrand.rs

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
use getrandom::Error;
77
#[macro_use]
88
extern crate cfg_if;
9-
#[path = "../src/lazy.rs"]
10-
mod lazy;
119
#[path = "../src/rdrand.rs"]
1210
mod rdrand;
1311
#[path = "../src/util.rs"]

0 commit comments

Comments
 (0)