From 033e50a70e3cde6f6de637eccccf2ff3ae77b35c Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 15 Dec 2024 10:44:44 +0100 Subject: [PATCH] Fix passing large arrays with JS values into Wasm detaching memory (#4353) --- CHANGELOG.md | 3 +++ crates/cli-support/src/js/mod.rs | 12 ++++------ crates/cli/tests/reference/echo.js | 4 ++-- crates/cli/tests/reference/typescript-type.js | 4 ++-- tests/wasm/js_vec.js | 8 +++++++ tests/wasm/js_vec.rs | 24 +++++++++++++++++++ tests/wasm/main.rs | 1 + 7 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 tests/wasm/js_vec.js create mode 100644 tests/wasm/js_vec.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 162bec367ec..524561857fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ 3. The name of an imported function if the function is not a method and does not have a `js_namespace` or `module` attribute. - Using JS keywords on imports in places other than the above will no longer cause the keywords to be escaped as `_{keyword}`. +* Fixed passing large arrays into Rust failing because of internal memory allocations invalidating the memory buffer. + [#4353](https://github.com/rustwasm/wasm-bindgen/pull/4353) + -------------------------------------------------------------------------------- ## [0.2.99](https://github.com/rustwasm/wasm-bindgen/compare/0.2.98...0.2.99) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index d33edbd8128..e129e1e280c 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1641,26 +1641,25 @@ __wbg_set_wasm(wasm);" let add = self.expose_add_to_externref_table(table, alloc)?; self.global(&format!( " - function {}(array, malloc) {{ + function {ret}(array, malloc) {{ const ptr = malloc(array.length * 4, 4) >>> 0; - const mem = {}(); for (let i = 0; i < array.length; i++) {{ - mem.setUint32(ptr + 4 * i, {}(array[i]), true); + const add = {add}(array[i]); + {mem}().setUint32(ptr + 4 * i, add, true); }} WASM_VECTOR_LEN = array.length; return ptr; }} ", - ret, mem, add, )); } _ => { self.expose_add_heap_object(); self.global(&format!( " - function {}(array, malloc) {{ + function {ret}(array, malloc) {{ const ptr = malloc(array.length * 4, 4) >>> 0; - const mem = {}(); + const mem = {mem}(); for (let i = 0; i < array.length; i++) {{ mem.setUint32(ptr + 4 * i, addHeapObject(array[i]), true); }} @@ -1668,7 +1667,6 @@ __wbg_set_wasm(wasm);" return ptr; }} ", - ret, mem, )); } } diff --git a/crates/cli/tests/reference/echo.js b/crates/cli/tests/reference/echo.js index b48c5e346e6..c786581f554 100644 --- a/crates/cli/tests/reference/echo.js +++ b/crates/cli/tests/reference/echo.js @@ -666,9 +666,9 @@ function addToExternrefTable0(obj) { function passArrayJsValueToWasm0(array, malloc) { const ptr = malloc(array.length * 4, 4) >>> 0; - const mem = getDataViewMemory0(); for (let i = 0; i < array.length; i++) { - mem.setUint32(ptr + 4 * i, addToExternrefTable0(array[i]), true); + const add = addToExternrefTable0(array[i]); + getDataViewMemory0().setUint32(ptr + 4 * i, add, true); } WASM_VECTOR_LEN = array.length; return ptr; diff --git a/crates/cli/tests/reference/typescript-type.js b/crates/cli/tests/reference/typescript-type.js index c69ecd4a682..0f861886fcf 100644 --- a/crates/cli/tests/reference/typescript-type.js +++ b/crates/cli/tests/reference/typescript-type.js @@ -49,9 +49,9 @@ function addToExternrefTable0(obj) { function passArrayJsValueToWasm0(array, malloc) { const ptr = malloc(array.length * 4, 4) >>> 0; - const mem = getDataViewMemory0(); for (let i = 0; i < array.length; i++) { - mem.setUint32(ptr + 4 * i, addToExternrefTable0(array[i]), true); + const add = addToExternrefTable0(array[i]); + getDataViewMemory0().setUint32(ptr + 4 * i, add, true); } WASM_VECTOR_LEN = array.length; return ptr; diff --git a/tests/wasm/js_vec.js b/tests/wasm/js_vec.js new file mode 100644 index 00000000000..2ceeeedb506 --- /dev/null +++ b/tests/wasm/js_vec.js @@ -0,0 +1,8 @@ +const assert = require('assert'); +const wasm = require('wasm-bindgen-test'); + +// Test if passing large arrays which cause allocation in Wasm are properly handled. +exports.pass_array_with_allocation = () => { + const values = new Array(10_000).fill(1) + assert.strictEqual(wasm.test_sum(values), 10_000); +}; diff --git a/tests/wasm/js_vec.rs b/tests/wasm/js_vec.rs new file mode 100644 index 00000000000..bba13561422 --- /dev/null +++ b/tests/wasm/js_vec.rs @@ -0,0 +1,24 @@ +use js_sys::Number; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen_test::wasm_bindgen_test; + +#[wasm_bindgen(module = "tests/wasm/js_vec.js")] +extern "C" { + fn pass_array_with_allocation(); +} + +#[wasm_bindgen] +pub fn test_sum(param: Vec) -> f64 { + let mut sum = 0.; + + for data in param { + sum += data.value_of(); + } + + sum +} + +#[wasm_bindgen_test] +fn test() { + pass_array_with_allocation(); +} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index a496aa1a3d0..b5640177fc1 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -40,6 +40,7 @@ pub mod inner_self; pub mod intrinsics; pub mod js_keywords; pub mod js_objects; +pub mod js_vec; pub mod jscast; pub mod link_to; pub mod macro_rules;