wasm-bindgen
wasm-bindgen copied to clipboard
Reading wrong address when memory usage exceeds 2GB
Describe the Bug
When memory usage exceeds 2GB, the glue code generated by wasm-pack reads the wrong address.
Steps to Reproduce
The following program uses 3GB of memory.
#[wasm_bindgen]
pub struct HugeData {
_data1: Vec<u32>,
data2: Vec<u32>,
}
#[wasm_bindgen]
impl HugeData {
pub fn new() -> Self {
let mut _data1 = vec![0; 3 << 27]; // 1.5 GB
let mut data2 = vec![0; 3 << 27]; // 1.5 GB
for i in 0..(3 << 27) {
_data1[i as usize] = i;
data2[i as usize] = i + (3 << 27);
}
Self { _data1, data2 }
}
pub fn get_last_element_as_boxed_slice(&self) -> Box<[u32]> {
self.data2[(3 << 27) - 1..].to_vec().into_boxed_slice()
}
}
Expected Behavior
get_last_element_as_boxed_slice() should return Uint32Array [ 805306367 ], where 805306367 is equal to (3 << 28) - 1.
Actual Behavior
In my environment, Uint32Array [ 537182218 ] was returned.
The glue code generated by wasm-pack is as follows:
/**
* @returns {Uint32Array}
*/
get_last_element_as_boxed_slice() {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.hugedata_get_last_element_as_boxed_slice(retptr, this.ptr);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v0 = getArrayU32FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 4);
return v0;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
Here, var r0 is a signed 32-bit integer, and it is negative when memory usage exceeds 2GB. Therefore, getArrayU32FromWasm0(r0, r1) reads memory of negative address, which causes this bug.
Thanks for the report! I think the generated JS hasn't ever been audited for pointers >= 2GB unfortunately. In theory this can be solved by sprinkling some >>> 0 additions in the code generation but I don't know how to best handle make sure everything is covered.