Skip to content

Commit f2c43e1

Browse files
committed
Don't use Uint8Array when not necessary
1 parent d804258 commit f2c43e1

File tree

3 files changed

+73
-37
lines changed

3 files changed

+73
-37
lines changed

.github/workflows/tests.yml

+30-14
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,27 @@ jobs:
229229
# run: cargo test
230230

231231
web:
232-
name: Web
232+
name: Web ${{ matrix.rust.description }}
233233
runs-on: ubuntu-24.04
234+
strategy:
235+
fail-fast: false
236+
matrix:
237+
rust:
238+
- { version: stable, atomics: false }
239+
- {
240+
description: with Atomics,
241+
atomics: true,
242+
version: nightly,
243+
components: rust-src,
244+
flags: '-Ctarget-feature=+atomics,+bulk-memory',
245+
args: '-Zbuild-std=panic_abort,std',
246+
}
234247
steps:
235248
- uses: actions/checkout@v4
236-
- uses: dtolnay/rust-toolchain@stable
249+
- uses: dtolnay/rust-toolchain@master
250+
with:
251+
toolchain: ${{ matrix.rust.version }}
252+
components: ${{ matrix.rust.components }}
237253
- name: Install precompiled wasm-pack
238254
shell: bash
239255
run: |
@@ -244,34 +260,34 @@ jobs:
244260
- uses: Swatinem/rust-cache@v2
245261
- name: Test (Node)
246262
env:
247-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
248-
run: wasm-pack test --node -- --features std
263+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
264+
run: wasm-pack test --node -- --features std ${{ matrix.rust.args }}
249265
- name: Test (Firefox)
250266
env:
251267
WASM_BINDGEN_USE_BROWSER: 1
252-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
253-
run: wasm-pack test --headless --firefox -- --features std
268+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
269+
run: wasm-pack test --headless --firefox -- --features std ${{ matrix.rust.args }}
254270
- name: Test (Chrome)
255271
env:
256272
WASM_BINDGEN_USE_BROWSER: 1
257-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
258-
run: wasm-pack test --headless --chrome -- --features std
273+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
274+
run: wasm-pack test --headless --chrome -- --features std ${{ matrix.rust.args }}
259275
- name: Test (dedicated worker)
260276
env:
261277
WASM_BINDGEN_USE_DEDICATED_WORKER: 1
262-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
263-
run: wasm-pack test --headless --firefox -- --features std
278+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
279+
run: wasm-pack test --headless --firefox -- --features std ${{ matrix.rust.args }}
264280
- name: Test (shared worker)
265281
env:
266282
WASM_BINDGEN_USE_SHARED_WORKER: 1
267-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
268-
run: wasm-pack test --headless --firefox -- --features std
283+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
284+
run: wasm-pack test --headless --firefox -- --features std ${{ matrix.rust.args }}
269285
- name: Test (service worker)
270286
env:
271287
WASM_BINDGEN_USE_SERVICE_WORKER: 1
272-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
288+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" ${{ matrix.rust.flags }}
273289
# Firefox doesn't support module service workers and therefor can't import scripts
274-
run: wasm-pack test --headless --chrome -- --features std
290+
run: wasm-pack test --headless --chrome -- --features std ${{ matrix.rust.args }}
275291

276292
wasi:
277293
name: WASI

.github/workflows/workspace.yml

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ jobs:
4949
env:
5050
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
5151
run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown
52+
- name: Web WASM with atomics (wasm_js.rs)
53+
env:
54+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory
55+
run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown
5256
- name: Linux (linux_android.rs)
5357
env:
5458
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"

src/backends/wasm_js.rs

+39-23
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,51 @@ pub use crate::util::{inner_u32, inner_u64};
77
#[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
88
compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!");
99

10+
#[cfg(target_feature = "atomics")]
1011
use js_sys::Uint8Array;
1112
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
1213

13-
// Size of our temporary Uint8Array buffer used with WebCrypto methods
14-
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
15-
const CRYPTO_BUFFER_SIZE: u16 = 256;
14+
// Maximum buffer size allowed in `Crypto.getRandomValuesSize` is 65536 bytes.
15+
// See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
16+
const MAX_BUFFER_SIZE: u16 = 256;
1617

1718
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
1819
CRYPTO.with(|crypto| {
1920
let crypto = crypto.as_ref().ok_or(Error::WEB_CRYPTO)?;
2021

21-
// getRandomValues does not work with all types of WASM memory,
22-
// so we initially write to browser memory to avoid exceptions.
23-
let buf = Uint8Array::new_with_length(CRYPTO_BUFFER_SIZE.into());
24-
for chunk in dest.chunks_mut(CRYPTO_BUFFER_SIZE.into()) {
25-
let chunk_len: u32 = chunk
26-
.len()
27-
.try_into()
28-
.expect("chunk length is bounded by CRYPTO_BUFFER_SIZE");
29-
// The chunk can be smaller than buf's length, so we call to
30-
// JS to create a smaller view of buf without allocation.
31-
let sub_buf = if chunk_len == u32::from(CRYPTO_BUFFER_SIZE) {
32-
buf.clone()
33-
} else {
34-
buf.subarray(0, chunk_len)
35-
};
36-
37-
if crypto.get_random_values(&sub_buf).is_err() {
38-
return Err(Error::WEB_GET_RANDOM_VALUES);
22+
#[cfg(not(target_feature = "atomics"))]
23+
{
24+
for chunk in dest.chunks_mut(MAX_BUFFER_SIZE.into()) {
25+
if crypto.get_random_values(chunk).is_err() {
26+
return Err(Error::WEB_GET_RANDOM_VALUES);
27+
}
3928
}
29+
}
30+
#[cfg(target_feature = "atomics")]
31+
{
32+
// getRandomValues does not work with all types of WASM memory,
33+
// so we initially write to browser memory to avoid exceptions.
34+
let buf = Uint8Array::new_with_length(MAX_BUFFER_SIZE.into());
35+
for chunk in dest.chunks_mut(MAX_BUFFER_SIZE.into()) {
36+
let chunk_len: u32 = chunk
37+
.len()
38+
.try_into()
39+
.expect("chunk length is bounded by MAX_BUFFER_SIZE");
40+
// The chunk can be smaller than buf's length, so we call to
41+
// JS to create a smaller view of buf without allocation.
42+
let sub_buf = if chunk_len == u32::from(MAX_BUFFER_SIZE) {
43+
buf.clone()
44+
} else {
45+
buf.subarray(0, chunk_len)
46+
};
47+
48+
if crypto.get_random_values(&sub_buf).is_err() {
49+
return Err(Error::WEB_GET_RANDOM_VALUES);
50+
}
4051

41-
// SAFETY: `sub_buf`'s length is the same length as `chunk`
42-
unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::<u8>()) };
52+
// SAFETY: `sub_buf`'s length is the same length as `chunk`
53+
unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::<u8>()) };
54+
}
4355
}
4456
Ok(())
4557
})
@@ -53,6 +65,10 @@ extern "C" {
5365
#[wasm_bindgen(thread_local_v2, js_name = crypto)]
5466
static CRYPTO: Option<Crypto>;
5567
// Crypto.getRandomValues()
68+
#[cfg(not(target_feature = "atomics"))]
69+
#[wasm_bindgen(method, js_name = getRandomValues, catch)]
70+
fn get_random_values(this: &Crypto, buf: &mut [MaybeUninit<u8>]) -> Result<(), JsValue>;
71+
#[cfg(target_feature = "atomics")]
5672
#[wasm_bindgen(method, js_name = getRandomValues, catch)]
5773
fn get_random_values(this: &Crypto, buf: &Uint8Array) -> Result<(), JsValue>;
5874
}

0 commit comments

Comments
 (0)