Skip to content

Commit

Permalink
Rollup merge of #99371 - ChrisDenton:simplify-gen-random-keys, r=thomcc
Browse files Browse the repository at this point in the history
Remove synchronization from Windows `hashmap_random_keys`

Unfortunately using synchronization when generating hashmap keys can prevent it being used in `DllMain`.

~~Fixes #99341~~
  • Loading branch information
Dylan-DPC authored Aug 3, 2022
2 parents e141246 + 46673bb commit 5730f12
Showing 1 changed file with 8 additions and 60 deletions.
68 changes: 8 additions & 60 deletions library/std/src/sys/windows/rand.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,9 @@
use crate::io;
use crate::mem;
use crate::sync;
use crate::ptr;
use crate::sys::c;

/// The kinds of HashMap RNG that may be available
#[derive(Clone, Copy, Debug, PartialEq)]
enum HashMapRng {
Preferred,
Fallback,
}

pub fn hashmap_random_keys() -> (u64, u64) {
match get_hashmap_rng() {
HashMapRng::Preferred => {
preferred_rng().expect("couldn't generate random bytes with preferred RNG")
}
HashMapRng::Fallback => {
fallback_rng().expect("couldn't generate random bytes with fallback RNG")
}
}
}

/// Returns the HashMap RNG that should be used
///
/// Panics if they are both broken
fn get_hashmap_rng() -> HashMapRng {
// Assume that if the preferred RNG is broken the first time we use it, it likely means
// that: the DLL has failed to load, there is no point to calling it over-and-over again,
// and we should cache the result
static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new();
*VALUE.get_or_init(choose_hashmap_rng)
}

/// Test whether we should use the preferred or fallback RNG
///
/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
/// we choose that
///
/// Panics if both the preferred and the fallback RNG are both non-functional
fn choose_hashmap_rng() -> HashMapRng {
let preferred_error = match preferred_rng() {
Ok(_) => return HashMapRng::Preferred,
Err(e) => e,
};

match fallback_rng() {
Ok(_) => return HashMapRng::Fallback,
Err(fallback_error) => panic!(
"preferred RNG broken: `{}`, fallback RNG broken: `{}`",
preferred_error, fallback_error
),
}
}

/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
fn preferred_rng() -> Result<(u64, u64), io::Error> {
use crate::ptr;

let mut v = (0, 0);
let ret = unsafe {
c::BCryptGenRandom(
Expand All @@ -66,22 +13,23 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};

if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
if ret != 0 { fallback_rng() } else { v }
}

/// Generate random numbers using the fallback RNG function (RtlGenRandom)
#[cfg(not(target_vendor = "uwp"))]
fn fallback_rng() -> Result<(u64, u64), io::Error> {
#[inline(never)]
fn fallback_rng() -> (u64, u64) {
let mut v = (0, 0);
let ret =
unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };

if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
}

/// We can't use RtlGenRandom with UWP, so there is no fallback
#[cfg(target_vendor = "uwp")]
fn fallback_rng() -> Result<(u64, u64), io::Error> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
#[inline(never)]
fn fallback_rng() -> (u64, u64) {
panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
}

0 comments on commit 5730f12

Please sign in to comment.