From 749ac6502f6fda5af26715b9908e4ca079926b8c Mon Sep 17 00:00:00 2001 From: Robert Masen Date: Sun, 17 Jun 2018 20:13:56 -0500 Subject: [PATCH 1/2] add ptr validation --- crates/backend/src/ast.rs | 1 + crates/cli-support/src/js/js2rust.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 8d1ac66c..9da6ed61 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -2,6 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream, TokenTree}; use quote::ToTokens; use shared; use syn; +use syn::AttrStyle; #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[derive(Default)] diff --git a/crates/cli-support/src/js/js2rust.rs b/crates/cli-support/src/js/js2rust.rs index c0d45787..00c24fdf 100644 --- a/crates/cli-support/src/js/js2rust.rs +++ b/crates/cli-support/src/js/js2rust.rs @@ -68,6 +68,9 @@ impl<'a, 'b> Js2Rust<'a, 'b> { /// passed should be `this.ptr`. pub fn method(&mut self, method: bool) -> &mut Self { if method { + self.prelude("if (this.ptr === 0) { + throw new Error('Attempt to use a moved value'); + }"); self.rust_arguments.insert(0, "this.ptr".to_string()); } self @@ -149,6 +152,9 @@ impl<'a, 'b> Js2Rust<'a, 'b> { } else { self.prelude(&format!("\ const ptr{i} = {arg}.ptr;\n\ + if (ptr{i} === 0) {{ + throw new Error('Attempt to use a moved value'); + }} {arg}.ptr = 0;\n\ ", i = i, arg = name)); self.rust_arguments.push(format!("ptr{}", i)); @@ -361,4 +367,4 @@ impl<'a, 'b> Js2Rust<'a, 'b> { let ts = format!("{} {}({}): {};\n", prefix, self.js_name, ts_args, self.ret_ty); (js, ts) } -} +} \ No newline at end of file From e9ea2dabc10cbf2991768cb60895440ddad99543 Mon Sep 17 00:00:00 2001 From: Robert Masen Date: Mon, 18 Jun 2018 15:34:48 -0500 Subject: [PATCH 2/2] add Validate ptr test --- tests/all/main.rs | 1 + tests/all/validate_prt.rs | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/all/validate_prt.rs diff --git a/tests/all/main.rs b/tests/all/main.rs index b909788a..2e7eaad0 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -538,3 +538,4 @@ mod structural; mod u64; mod webidl; mod comments; +mod validate_prt; \ No newline at end of file diff --git a/tests/all/validate_prt.rs b/tests/all/validate_prt.rs new file mode 100644 index 00000000..53c59a65 --- /dev/null +++ b/tests/all/validate_prt.rs @@ -0,0 +1,69 @@ +use super::project; + +#[test] +fn works() { + 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 struct Fruit { + name: String, + } + #[wasm_bindgen] + impl Fruit { + #[wasm_bindgen(method)] + pub fn name(&self) -> String { + self.name.clone() + } + #[wasm_bindgen(constructor)] + pub fn new(name: String) -> Self { + Fruit { + name, + } + } + } + #[wasm_bindgen] + pub fn eat(_fruit: Fruit) { } + "#) + .file("test.js", r#" + import * as wasm from './out'; + const targetMessage = 'Attempt to use a moved value'; + function assertEq(a, b) { + console.log(a, '?=', b); + if (a === b) + return; + throw new Error('not equal'); + } + export function test() { + useMoved(); + moveMoved(); + } + export function useMoved() { + // create a new struct + let apple = new wasm.Fruit('apple'); + // sanity check that this method works + let name = apple.name(); + // consume the struct + wasm.eat(apple); + // try and use the moved apple again + try { + let movedName = apple.name(); + } catch (e) { + assertEq(e.message, targetMessage); + } + } + export function moveMoved() { + let pear = new wasm.Fruit('pear'); + let name = pear.name(); + wasm.eat(pear); + try { + wasm.eat(pear); + } catch (e) { + assertEq(e.message, targetMessage); + } + } + "#) + .test(); +}