diff --git a/.cargo/config.toml b/.cargo/config.toml index 567208e3..716482d6 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,8 @@ # Allow normal use of "cargo run" and "cargo test" on these wasm32 platforms. [target.wasm32-unknown-unknown] runner = 'wasm-bindgen-test-runner' +[target.wasm32v1-unknown] +runner = 'wasm-bindgen-test-runner' [target.wasm32-wasip1] runner = 'wasmtime' [target.wasm32-wasip2] diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6e92dae0..045a6bb9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -245,33 +245,33 @@ jobs: - name: Test (Node) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --node + run: wasm-pack test --node -- --features std - name: Test (Firefox) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (Chrome) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --chrome + run: wasm-pack test --headless --chrome -- --features std - name: Test (dedicated worker) env: WASM_BINDGEN_USE_DEDICATED_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (shared worker) env: WASM_BINDGEN_USE_SHARED_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (service worker) env: WASM_BINDGEN_USE_SERVICE_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" # Firefox doesn't support module service workers and therefor can't import scripts - run: wasm-pack test --headless --chrome + run: wasm-pack test --headless --chrome -- --features std wasi: name: WASI diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 2653984d..ce440db9 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2024-10-08 + toolchain: nightly-2024-10-24 components: clippy,rust-src - name: std feature run: cargo clippy --features std @@ -48,7 +48,23 @@ jobs: - name: Web WASM (wasm_js.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown + run: cargo clippy --features std -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown + - name: Web WASM no_std (wasm_js.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: cargo clippy -Zbuild-std=core,alloc --target wasm32-unknown-unknown + - name: Web WASM no_std with atomics (wasm_js.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory + run: cargo clippy -Zbuild-std=core,alloc --target wasm32-unknown-unknown + - name: Web WASMv1 (wasm_js.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: cargo clippy -Zbuild-std=core,alloc --target wasm32v1-none + - name: Web WASMv1 with atomics (wasm_js.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory + run: cargo clippy -Zbuild-std=core,alloc --target wasm32v1-none - name: Linux (linux_android.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" diff --git a/Cargo.toml b/Cargo.toml index 28b48a64..79d146b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,16 +63,17 @@ wasi = { version = "0.13", default-features = false } windows-targets = "0.52" # wasm_js -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dependencies] -wasm-bindgen = { version = "0.2.89", default-features = false } -js-sys = "0.3" -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] -wasm-bindgen-test = "0.3.39" +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] +wasm-bindgen = { version = "0.2.96", default-features = false } +js-sys = { version = "0.3.73", default-features = false } +once_cell = { version = "1", default-features = false } +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] +wasm-bindgen-test = { version = "0.3", default-features = false } [features] # Implement std::error::Error for getrandom::Error and # use std to retrieve OS error descriptions -std = [] +std = ["wasm-bindgen/std", "js-sys/std", "wasm-bindgen-test/std"] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] diff --git a/README.md b/README.md index d145c2fe..7d569b8b 100644 --- a/README.md +++ b/README.md @@ -76,15 +76,15 @@ Pull Requests that add support for new targets to `getrandom` are always welcome `getrandom` also provides optional (opt-in) backends, which allow users to customize the source of randomness based on their specific needs: -| Backend name | Target | Target Triple | Implementation -| ----------------- | -------------------- | ------------------------ | -------------- -| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). -| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. -| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction -| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! -| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) -| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) +| Backend name | Target | Target Triple | Implementation +| ----------------- | -------------------- | ----------------------------------------- | -------------- +| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. +| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction +| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register +| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! +| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) +| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. The flag can be set either by specifying the `rustflags` field in diff --git a/src/backends.rs b/src/backends.rs index a744a229..fee46991 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -150,11 +150,12 @@ cfg_if! { pub use rdrand::*; } else if #[cfg(all( target_arch = "wasm32", - target_os = "unknown", + any(target_os = "unknown", target_os = "none"), ))] { - compile_error!("the wasm32-unknown-unknown targets are not supported \ - by default, you may need to enable the \"wasm_js\" \ - configuration flag. For more information see: \ + compile_error!("the wasm32-unknown-unknown and wasm32v1-none targets \ + are not supported by default, you may need to enable \ + the \"wasm_js\" configuration flag. For more \ + information see: \ https://docs.rs/getrandom/#webassembly-support"); } else { compile_error!("target is not supported. You may need to define \ diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 15a4e66b..a7e5a48f 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -1,15 +1,18 @@ //! Implementation for WASM based on Web and Node.js use crate::Error; +#[cfg(feature = "std")] extern crate std; -use std::{mem::MaybeUninit, thread_local}; +use core::mem::MaybeUninit; pub use crate::util::{inner_u32, inner_u64}; -#[cfg(not(all(target_arch = "wasm32", target_os = "unknown",)))] +#[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"),)))] compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!"); use js_sys::{global, Function, Uint8Array}; +#[cfg(not(feature = "std"))] +use once_cell::unsync::Lazy; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; // Size of our temporary Uint8Array buffer used with WebCrypto methods @@ -25,12 +28,37 @@ enum RngSource { // JsValues are always per-thread, so we initialize RngSource for each thread. // See: https://github.com/rustwasm/wasm-bindgen/pull/955 -thread_local!( - static RNG_SOURCE: Result = getrandom_init(); -); +struct Local; + +impl Local { + #[cfg(feature = "std")] + fn with(f: impl FnOnce(&Result) -> R) -> R { + std::thread_local!( + static RNG_SOURCE: Result = getrandom_init(); + ); + RNG_SOURCE.with(f) + } + + #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] + fn with(f: impl FnOnce(&Result) -> R) -> R { + struct Wrapper(T); + unsafe impl Send for Wrapper {} + unsafe impl Sync for Wrapper {} + static RNG_SOURCE: Wrapper>> = + Wrapper(Lazy::new(getrandom_init)); + f(&RNG_SOURCE.0) + } + + #[cfg(all(not(feature = "std"), target_feature = "atomics"))] + fn with(f: impl FnOnce(&Result) -> R) -> R { + #[thread_local] + static RNG_SOURCE: Lazy> = Lazy::new(getrandom_init); + f(&RNG_SOURCE) + } +} pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - RNG_SOURCE.with(|result| { + Local::with(|result| { let source = result.as_ref().map_err(|&e| e)?; match source { diff --git a/src/lib.rs b/src/lib.rs index 5b0f47fd..090efa34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,16 @@ #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(getrandom_sanitize, feature(cfg_sanitize))] +#![cfg_attr( + all( + getrandom_backend = "wasm_js", + target_arch = "wasm32", + any(target_os = "unknown", target_os = "none"), + not(feature = "std"), + target_feature = "atomics" + ), + feature(thread_local) +)] #![deny( clippy::cast_lossless, clippy::cast_possible_truncation,