As opposed to the generated code when accepting a &str, wasm-bindgen will not free Vec<u8> aka Uint8Array after it has been passed to Rust.
We investigated this issue after several customers reported a Chrome crash related to memory exhaustion and found big Uint8Array passed to the WebAssembly module to keep growing the memory use, eventually running into memory issues.
Example code:
#[wasm_bindgen]
pub fn process(data: String) -> String {
process_bytes(data.to_string().to_vec())
}
Generated binding code:
__exports.process = function(data) {
const ptr0 = passStringToWasm(data);
const len0 = WASM_VECTOR_LEN;
const retptr = globalArgumentPtr();
try {
wasm.process(retptr, ptr0, len0);
const mem = getUint32Memory();
const rustptr = mem[retptr / 4];
const rustlen = mem[retptr / 4 + 1];
const realRet = getStringFromWasm(rustptr, rustlen).slice();
wasm.__wbindgen_free(rustptr, rustlen * 1);
return realRet;
} finally {
wasm.__wbindgen_free(ptr0, len0 * 1);
}
}
Note how ptr0 (const ptr0 = passStringToWasm(data);) is freed in the finally block at the end of the method: wasm.__wbindgen_free(ptr0, len0 * 1);. That said, the return realRet; in the try block will probably prevent ptr0 from ever being freed in the finally block.
Compare the output when expecting a Vec<u8>:
Example code:
#[wasm_bindgen]
pub fn process(data: Vec<u8>) -> String {
process_bytes(data)
}
Generated binding code:
__exports. process = function(data) {
const ptr0 = passArray8ToWasm(data);
const len0 = WASM_VECTOR_LEN;
const retptr = globalArgumentPtr();
wasm.process(retptr, ptr0, len0);
const mem = getUint32Memory();
const rustptr = mem[retptr / 4];
const rustlen = mem[retptr / 4 + 1];
const realRet = getStringFromWasm(rustptr, rustlen).slice();
wasm.__wbindgen_free(rustptr, rustlen * 1);
return realRet;
}
ptr0 is allocated (const ptr0 = passArray8ToWasm(data);) but never freed.
As opposed to the generated code when accepting a
&str, wasm-bindgen will not freeVec<u8>aka Uint8Array after it has been passed to Rust.We investigated this issue after several customers reported a Chrome crash related to memory exhaustion and found big
Uint8Arraypassed to the WebAssembly module to keep growing the memory use, eventually running into memory issues.Example code:
Generated binding code:
Note how
ptr0(const ptr0 = passStringToWasm(data);) is freed in thefinallyblock at the end of the method:wasm.__wbindgen_free(ptr0, len0 * 1);. That said, thereturn realRet;in thetryblock will probably preventptr0from ever being freed in thefinallyblock.Compare the output when expecting a
Vec<u8>:Example code:
Generated binding code:
ptr0is allocated (const ptr0 = passArray8ToWasm(data);) but never freed.