Merge pull request #6645 from dotCooCoo/fix/js-random-seed-web

Scripts: Math.random gets a new seed on every web page load
This commit is contained in:
BFlat
2026-11-12 02:24:16 +07:00
committed by GitHub
4 changed files with 26 additions and 5 deletions
Generated
+1
View File
@@ -6589,6 +6589,7 @@ name = "vectorcraft-js"
version = "0.24.0"
dependencies = [
"chrono",
"getrandom 0.4.3",
"proptest",
"unicode-general-category",
]
+6
View File
@@ -12,6 +12,12 @@ workspace = true
[dependencies]
chrono = { workspace = true }
unicode-general-category = "1"
# The seed of Math.random (interp.rs).
getrandom = "0.4"
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
# The browser's crypto.getRandomValues.
getrandom = { version = "0.4", features = ["wasm_js"] }
[dev-dependencies]
proptest = { workspace = true }
+11
View File
@@ -605,6 +605,17 @@ fn math_functions_follow_the_special_cases() {
truth("var n = 0; Math.max({valueOf: function () { n++; return NaN; }}, {valueOf: function () { n++; return 1; }}); n === 2");
}
#[test]
fn math_random_is_seeded_from_the_os_random_source() {
// On wasm32-unknown-unknown `RandomState`'s keys come from memory addresses, which are the
// same on every page load: the seed must come from the OS (the browser's crypto) instead.
let src = include_str!("interp.rs");
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");
}
// ---- JSON ----
#[test]
+8 -5
View File
@@ -307,13 +307,16 @@ fn index_keys_bytes(len: usize) -> usize {
total
}
/// A seed for `Math.random` that differs from realm to realm, from the standard library's
/// randomly keyed hasher; never zero.
/// A seed for `Math.random` that differs from realm to realm and from run to run, from the OS
/// 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 {
use std::hash::{BuildHasher, Hasher};
let mut h = std::collections::hash_map::RandomState::new().build_hasher();
h.write_u64(0x9e37_79b9_7f4a_7c15);
h.finish() | 1
getrandom::u64().unwrap_or_else(|_| {
let mut h = std::collections::hash_map::RandomState::new().build_hasher();
h.write_u64(0x9e37_79b9_7f4a_7c15);
h.finish()
}) | 1
}
/// The estimated bytes of a binding or property named by `len` code units.