diff --git a/crates/js/src/builtins_tests.rs b/crates/js/src/builtins_tests.rs index 9d917ae32..0a70e8043 100644 --- a/crates/js/src/builtins_tests.rs +++ b/crates/js/src/builtins_tests.rs @@ -613,7 +613,11 @@ fn math_random_is_seeded_from_the_os_random_source() { let Some(start) = src.find("fn random_seed()") else { panic!("interp.rs has no random_seed") }; let body = &src[start..]; let body = &body[..body.find("\n}").unwrap_or(body.len())]; - assert!(body.contains("getrandom::u64()"), "Math.random isn't seeded from the OS random source"); + assert!(body.contains("random_seed_from(getrandom::u64())"), "Math.random isn't seeded from the OS random source"); + // The OS value is the seed, made odd so it's never zero; a failed read still gives a seed. + assert_eq!(crate::interp::random_seed_from(Ok(0x40)), 0x41); + assert_eq!(crate::interp::random_seed_from(Ok(0)), 1); + assert_eq!(crate::interp::random_seed_from(Err(getrandom::Error::UNSUPPORTED)) & 1, 1); } // ---- JSON ---- diff --git a/crates/js/src/interp.rs b/crates/js/src/interp.rs index 5d59d92d2..4f6a78a39 100644 --- a/crates/js/src/interp.rs +++ b/crates/js/src/interp.rs @@ -311,8 +311,13 @@ fn index_keys_bytes(len: usize) -> usize { /// random source (the browser's crypto on the web), or the standard library's randomly keyed /// hasher when that fails; never zero. fn random_seed() -> u64 { + random_seed_from(getrandom::u64()) +} + +/// [`random_seed`] from what the OS random source returned. +pub(crate) fn random_seed_from(os: Result) -> u64 { use std::hash::{BuildHasher, Hasher}; - getrandom::u64().unwrap_or_else(|_| { + os.unwrap_or_else(|_| { let mut h = std::collections::hash_map::RandomState::new().build_hasher(); h.write_u64(0x9e37_79b9_7f4a_7c15); h.finish()