mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-12-25 19:11:45 +03:00
Prevent use-after-free with vectors
Awhile back slices switched to being raw views into wasm memory, but this doens't work if we free the underlying memory unconditionally! Moving around a `Vec` is already moving a lot of data, so let's copy it onto the JS heap instead of leaving it in the wasm heap.
This commit is contained in:
parent
cfe7ebd463
commit
dd76707ea1
@ -256,7 +256,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
const mem = getUint32Memory();\n\
|
const mem = getUint32Memory();\n\
|
||||||
const ptr = mem[retptr / 4];\n\
|
const ptr = mem[retptr / 4];\n\
|
||||||
const len = mem[retptr / 4 + 1];\n\
|
const len = mem[retptr / 4 + 1];\n\
|
||||||
const realRet = {}(ptr, len);\n\
|
const realRet = {}(ptr, len).slice();\n\
|
||||||
wasm.__wbindgen_free(ptr, len * {});\n\
|
wasm.__wbindgen_free(ptr, len * {});\n\
|
||||||
return realRet;\n\
|
return realRet;\n\
|
||||||
", f, ty.size());
|
", f, ty.size());
|
||||||
|
@ -90,6 +90,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
|
|
||||||
if !arg.is_by_ref() {
|
if !arg.is_by_ref() {
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
|
v{0} = v{0}.slice();\n\
|
||||||
wasm.__wbindgen_free({0}, {1} * {size});\
|
wasm.__wbindgen_free({0}, {1} * {size});\
|
||||||
", abi, abi2, size = ty.size()));
|
", abi, abi2, size = ty.size()));
|
||||||
self.cx.require_internal_export("__wbindgen_free")?;
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
|
@ -416,3 +416,76 @@ fn export_mut() {
|
|||||||
.test();
|
.test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_vec_ok() {
|
||||||
|
project()
|
||||||
|
.file("src/lib.rs", r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn broken_vec() -> Vec<u32> {
|
||||||
|
vec![1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn web_main() -> Application {
|
||||||
|
Application::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct Application {
|
||||||
|
thing: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Application {
|
||||||
|
pub fn new() -> Application {
|
||||||
|
let mut thing = vec![];
|
||||||
|
thing.push(0);
|
||||||
|
thing.push(0);
|
||||||
|
thing.push(0);
|
||||||
|
thing.push(0);
|
||||||
|
thing.push(0);
|
||||||
|
|
||||||
|
Application {
|
||||||
|
thing: thing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn tick(&mut self) {
|
||||||
|
self.thing = self.thing.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as assert from "assert";
|
||||||
|
import * as wasm from "./out";
|
||||||
|
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
let app = wasm.web_main();
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
app.tick();
|
||||||
|
let bad = wasm.broken_vec();
|
||||||
|
console.log("Received from rust:", i, bad);
|
||||||
|
assert.strictEqual(bad[0], 1);
|
||||||
|
assert.strictEqual(bad[1], 2);
|
||||||
|
assert.strictEqual(bad[2], 3);
|
||||||
|
assert.strictEqual(bad[3], 4);
|
||||||
|
assert.strictEqual(bad[4], 5);
|
||||||
|
assert.strictEqual(bad[5], 6);
|
||||||
|
assert.strictEqual(bad[6], 7);
|
||||||
|
assert.strictEqual(bad[7], 8);
|
||||||
|
assert.strictEqual(bad[8], 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user