about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/path/tests.rs1
-rw-r--r--library/std/src/process.rs2
-rw-r--r--library/std/src/sys/windows/c.rs4
-rw-r--r--library/std/src/sys/windows/rand.rs74
4 files changed, 76 insertions, 5 deletions
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 0d8ea29c2be..351cf698810 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -7,6 +7,7 @@ use crate::rc::Rc;
 use crate::sync::Arc;
 use core::hint::black_box;
 
+#[allow(unknown_lints, unused_macro_rules)]
 macro_rules! t (
     ($path:expr, iter: $iter:expr) => (
         {
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 6c5c08d0bea..e253f46406f 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1764,7 +1764,7 @@ impl ExitCode {
     ///     code.exit_process()
     /// }
     /// ```
-    #[unstable(feature = "exitcode_exit_method", issue = "none")]
+    #[unstable(feature = "exitcode_exit_method", issue = "97100")]
     pub fn exit_process(self) -> ! {
         exit(self.to_i32())
     }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 0692da1d795..0bb6fee60c9 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -788,6 +788,10 @@ if #[cfg(not(target_vendor = "uwp"))] {
 
     #[link(name = "advapi32")]
     extern "system" {
+        // Forbidden when targeting UWP
+        #[link_name = "SystemFunction036"]
+        pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
+
         // Allowed but unused by UWP
         pub fn OpenProcessToken(
             ProcessHandle: HANDLE,
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index de73e9154b4..22e024d8552 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,8 +1,60 @@
 use crate::io;
+use crate::lazy;
 use crate::mem;
 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: lazy::SyncOnceCell<HashMapRng> = lazy::SyncOnceCell::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);
@@ -14,8 +66,22 @@ pub fn hashmap_random_keys() -> (u64, u64) {
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
     };
-    if ret != 0 {
-        panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-    }
-    return v;
+
+    if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+}
+
+/// Generate random numbers using the fallback RNG function (RtlGenRandom)
+#[cfg(not(target_vendor = "uwp"))]
+fn fallback_rng() -> Result<(u64, u64), io::Error> {
+    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()) }
+}
+
+/// 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"))
 }