Skip to content

Generated binding code does not free malloc'd data after passed to Rust if it's a Vec<u8> #1515

Description

@19h

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions