From 3596c940a07af606ca2f081a529b78c535af7c45 Mon Sep 17 00:00:00 2001 From: Gentle Date: Sun, 19 Jan 2025 16:22:27 +0100 Subject: [PATCH 01/10] add option for reference_types only enables the wasmtime feature, which allows initializing Modules that were compiled with newer llvm versions but don't actually use reference_types Disabled by default --- src/lib.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f52b882..6ae9733 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ const DEFAULT_WASM_MULTI_VALUE: bool = true; const DEFAULT_WASM_MULTI_MEMORY: bool = true; const DEFAULT_WASM_BULK_MEMORY: bool = false; const DEFAULT_WASM_SIMD: bool = true; +const DEFAULT_WASM_REFERENCE_TYPES: bool = false; /// The type of data that is stored in the `wasmtime::Store` during /// initialization. @@ -249,6 +250,15 @@ pub struct Wizer { /// Enabled by default. #[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))] wasm_simd: Option, + + /// Enable or disable the Wasm reference-types proposal. + /// + /// Currently does not implement any reference-types specific code, + /// but enables initializing Modules that have reference-types enabled + /// + /// Disabled by default. + #[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))] + wasm_reference_types: Option, } impl std::fmt::Debug for Wizer { @@ -269,6 +279,7 @@ impl std::fmt::Debug for Wizer { wasm_multi_value, wasm_bulk_memory, wasm_simd, + wasm_reference_types, } = self; f.debug_struct("Wizer") .field("init_func", &init_func) @@ -286,6 +297,7 @@ impl std::fmt::Debug for Wizer { .field("wasm_multi_value", &wasm_multi_value) .field("wasm_bulk_memory", &wasm_bulk_memory) .field("wasm_simd", &wasm_simd) + .field("wasm_reference_types", &wasm_reference_types) .finish() } } @@ -350,6 +362,7 @@ impl Wizer { wasm_multi_value: None, wasm_bulk_memory: None, wasm_simd: None, + wasm_reference_types: None, } } @@ -632,8 +645,14 @@ impl Wizer { config.wasm_simd(self.wasm_simd.unwrap_or(DEFAULT_WASM_SIMD)); + // Note that reference_types are not actually supported, + // but many compilers now enable them by default + config.wasm_reference_types( + self.wasm_reference_types + .unwrap_or(DEFAULT_WASM_REFERENCE_TYPES), + ); + // Proposals that we should add support for. - config.wasm_reference_types(false); config.wasm_threads(false); Ok(config) @@ -654,7 +673,9 @@ impl Wizer { multi_value: self.wasm_multi_value.unwrap_or(DEFAULT_WASM_MULTI_VALUE), // Proposals that we should add support for. - reference_types: false, + reference_types: self + .wasm_reference_types + .unwrap_or(DEFAULT_WASM_REFERENCE_TYPES), simd: self.wasm_simd.unwrap_or(DEFAULT_WASM_SIMD), threads: false, tail_call: false, From 1ed9b19141b15d528a777c2b4c63b45fcc4f5b9e Mon Sep 17 00:00:00 2001 From: Gentle Date: Fri, 24 Jan 2025 20:44:16 +0100 Subject: [PATCH 02/10] Update src/lib.rs Co-authored-by: Nick Fitzgerald --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6ae9733..6d6a5ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,8 +253,9 @@ pub struct Wizer { /// Enable or disable the Wasm reference-types proposal. /// - /// Currently does not implement any reference-types specific code, - /// but enables initializing Modules that have reference-types enabled + /// Currently does not implement snapshotting or the use of references, + /// but enables initializing Wasm modules that use encodings introduced + /// in the reference-types proposal. /// /// Disabled by default. #[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))] From 24a2408b7b5c1bf95d6b3b62d74149d4a06d3ef6 Mon Sep 17 00:00:00 2001 From: Gentle Date: Fri, 24 Jan 2025 21:39:02 +0100 Subject: [PATCH 03/10] reject reference-types related instructions --- src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6d6a5ea..a665374 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -754,6 +754,30 @@ impl Wizer { wasmparser::Operator::TableSet { .. } => { unreachable!("part of reference types") } + wasmparser::Operator::RefNull { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::RefIsNull => { + unreachable!("part of reference types") + } + wasmparser::Operator::TypedSelect { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::RefFunc { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::TableGet { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::TableSize { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::TableGrow { .. } => { + unreachable!("part of reference types") + } + wasmparser::Operator::TableFill { .. } => { + unreachable!("part of reference types") + } _ => continue, } } From c1a72d84ce82a64ab3689492683de2c31afda678 Mon Sep 17 00:00:00 2001 From: Gentle Date: Sat, 25 Jan 2025 18:28:53 +0100 Subject: [PATCH 04/10] add setter for wasm_reference_types --- src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a665374..50541a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -570,6 +570,14 @@ impl Wizer { self } + /// Enable or disable the Wasm reference-types proposal. + /// + /// Defaults to `false`. + pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self { + self.wasm_reference_types = Some(enable); + self + } + /// Initialize the given Wasm, snapshot it, and return the serialized /// snapshot as a new, pre-initialized Wasm module. pub fn run(&self, wasm: &[u8]) -> anyhow::Result> { From b4443dd8562a829ffc378211ad03087ab82e358f Mon Sep 17 00:00:00 2001 From: Gentle Date: Sat, 25 Jan 2025 18:43:47 +0100 Subject: [PATCH 05/10] bail instead of unreachable --- src/lib.rs | 18 +++++++++--------- tests/tests.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 50541a9..ddc80e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -760,31 +760,31 @@ impl Wizer { anyhow::bail!("unsupported `data.drop` instruction") } wasmparser::Operator::TableSet { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::RefNull { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::RefIsNull => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::TypedSelect { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::RefFunc { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::TableGet { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::TableSize { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::TableGrow { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } wasmparser::Operator::TableFill { .. } => { - unreachable!("part of reference types") + anyhow::bail!("part of reference types") } _ => continue, } diff --git a/tests/tests.rs b/tests/tests.rs index 66c2f3f..ddade50 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -727,3 +727,33 @@ fn accept_simd128() -> Result<()> { "#, ) } + +#[test] +fn reject_table_grow_with_reference_types_enabled() -> anyhow::Result<()> { + let wat = r#" + (module + (elem declare func $f) + (func $f) + (table 0 funcref) + (func (export "_initialize") (result i32) + ref.func $f + i32.const 1 + table.grow + ) + )"#; + + let _ = env_logger::try_init(); + let mut wizer = Wizer::new(); + wizer.wasm_reference_types(true); + let result = run_wat(&[], 42, wat); + + assert!(result.is_err()); + + let err = result.unwrap_err(); + dbg!(&err); + assert!(err + .to_string() + .contains("reference types support is not enabled")); + + Ok(()) +} From 174b8d4717d7dd384ec190282c77add8cc4bb1fc Mon Sep 17 00:00:00 2001 From: Gentle Date: Sat, 25 Jan 2025 18:44:52 +0100 Subject: [PATCH 06/10] tests for reference-types still rejecting tyble modifying instructions --- tests/tests.rs | 95 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index ddade50..d6cb5ca 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -269,6 +269,71 @@ fn reject_table_get_set() -> Result<()> { Ok(()) } +#[test] +fn reject_table_get_set_with_reference_types_enabled() -> Result<()> { + let wat = r#" + (module + (table 3 funcref) + + (func $f (result i32) (i32.const 0)) + (func $g (result i32) (i32.const 0)) + (func $h (result i32) (i32.const 0)) + + (func (export "main") + i32.const 0 + i32.const 1 + table.get + table.set) + + (elem (i32.const 0) $f $g $h) + )"#; + + let _ = env_logger::try_init(); + let mut wizer = Wizer::new(); + wizer.wasm_reference_types(true); + + let wasm = wat_to_wasm(wat)?; + let result = wizen_and_run_wasm(&[], 42, &wasm, wizer); + + assert!(result.is_err()); + + let err = result.unwrap_err(); + dbg!(&err); + assert!(err.to_string().contains("part of reference types"),); + + Ok(()) +} + +#[test] +fn reject_table_grow_with_reference_types_enabled() -> anyhow::Result<()> { + let wat = r#" + (module + (elem declare func $f) + (func $f) + (table 0 funcref) + (func (export "_initialize") (result i32) + ref.func $f + i32.const 1 + table.grow + ) + )"#; + + let _ = env_logger::try_init(); + let mut wizer = Wizer::new(); + wizer.wasm_reference_types(true); + + let wasm = wat_to_wasm(wat)?; + let result = wizen_and_run_wasm(&[], 42, &wasm, wizer); + + assert!(result.is_err()); + + let err = result.unwrap_err(); + dbg!(&err); + assert!(err.to_string().contains("part of reference types")); + + Ok(()) +} + #[test] fn reject_table_init() -> Result<()> { let result = run_wat( @@ -727,33 +792,3 @@ fn accept_simd128() -> Result<()> { "#, ) } - -#[test] -fn reject_table_grow_with_reference_types_enabled() -> anyhow::Result<()> { - let wat = r#" - (module - (elem declare func $f) - (func $f) - (table 0 funcref) - (func (export "_initialize") (result i32) - ref.func $f - i32.const 1 - table.grow - ) - )"#; - - let _ = env_logger::try_init(); - let mut wizer = Wizer::new(); - wizer.wasm_reference_types(true); - let result = run_wat(&[], 42, wat); - - assert!(result.is_err()); - - let err = result.unwrap_err(); - dbg!(&err); - assert!(err - .to_string() - .contains("reference types support is not enabled")); - - Ok(()) -} From f4cf24205d75891030690a767bdbb74382b8f155 Mon Sep 17 00:00:00 2001 From: Gentle Date: Sat, 25 Jan 2025 19:58:11 +0100 Subject: [PATCH 07/10] better error messages --- src/lib.rs | 22 +++++++++++----------- tests/tests.rs | 10 ++++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ddc80e7..2aa1aee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -760,31 +760,31 @@ impl Wizer { anyhow::bail!("unsupported `data.drop` instruction") } wasmparser::Operator::TableSet { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `table.set` instruction") + } + wasmparser::Operator::TableGet { .. } => { + anyhow::bail!("unsupported `table.get` instruction") } wasmparser::Operator::RefNull { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `ref.null` instruction") } wasmparser::Operator::RefIsNull => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `ref.is_null` instruction") } wasmparser::Operator::TypedSelect { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported typed `select` instruction") } wasmparser::Operator::RefFunc { .. } => { - anyhow::bail!("part of reference types") - } - wasmparser::Operator::TableGet { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `ref.func` instruction") } wasmparser::Operator::TableSize { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `table.size` instruction") } wasmparser::Operator::TableGrow { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `table.grow` instruction") } wasmparser::Operator::TableFill { .. } => { - anyhow::bail!("part of reference types") + anyhow::bail!("unsupported `table.fill` instruction") } _ => continue, } diff --git a/tests/tests.rs b/tests/tests.rs index d6cb5ca..b8bd4d4 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -298,8 +298,9 @@ fn reject_table_get_set_with_reference_types_enabled() -> Result<()> { assert!(result.is_err()); let err = result.unwrap_err(); - dbg!(&err); - assert!(err.to_string().contains("part of reference types"),); + assert!(err + .to_string() + .contains("unsupported `table.get` instruction"),); Ok(()) } @@ -328,8 +329,9 @@ fn reject_table_grow_with_reference_types_enabled() -> anyhow::Result<()> { assert!(result.is_err()); let err = result.unwrap_err(); - dbg!(&err); - assert!(err.to_string().contains("part of reference types")); + assert!(err + .to_string() + .contains("unsupported `ref.func` instruction")); Ok(()) } From eedaef4186e1d794cd738706902257c6a705e248 Mon Sep 17 00:00:00 2001 From: Gentle Date: Sat, 25 Jan 2025 20:30:56 +0100 Subject: [PATCH 08/10] test indirect call with reference_types enabled --- tests/tests.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/tests.rs b/tests/tests.rs index b8bd4d4..bd0362f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -336,6 +336,32 @@ fn reject_table_grow_with_reference_types_enabled() -> anyhow::Result<()> { Ok(()) } +#[test] +fn indirect_call_with_reference_types() -> anyhow::Result<()> { + let wat = r#" + (module + (type $sig (func (result i32))) + (table 1 funcref) + (elem (i32.const 0) $f) + (func $f (type $sig) + i32.const 42 + ) + (func (export "wizer.initialize")) + (func (export "run") (result i32) + i32.const 0 + call_indirect (type $sig) + ) + )"#; + + let _ = env_logger::try_init(); + let mut wizer = Wizer::new(); + wizer.wasm_reference_types(true); + wizer.wasm_bulk_memory(true); + + let wasm = wat_to_wasm(wat)?; + wizen_and_run_wasm(&[], 42, &wasm, wizer) +} + #[test] fn reject_table_init() -> Result<()> { let result = run_wat( From 55e8bc1210f612b99f806fc4816ef4ed3bbe31a9 Mon Sep 17 00:00:00 2001 From: Gentle Date: Tue, 28 Jan 2025 21:08:09 +0100 Subject: [PATCH 09/10] same docstring for library and cli --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2aa1aee..9194ce3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -572,6 +572,10 @@ impl Wizer { /// Enable or disable the Wasm reference-types proposal. /// + /// Currently does not implement snapshotting or the use of references, + /// but enables initializing Wasm modules that use encodings introduced + /// in the reference-types proposal. + /// /// Defaults to `false`. pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self { self.wasm_reference_types = Some(enable); From 27e0fd202f23a6c86fcbca54d863100b293b7ffa Mon Sep 17 00:00:00 2001 From: Gentle Date: Tue, 28 Jan 2025 21:08:48 +0100 Subject: [PATCH 10/10] (hopefully) actually use the new call_indirect --- tests/tests.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index bd0362f..e7d1873 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -341,15 +341,16 @@ fn indirect_call_with_reference_types() -> anyhow::Result<()> { let wat = r#" (module (type $sig (func (result i32))) - (table 1 funcref) - (elem (i32.const 0) $f) + (table 0 funcref) + (table $table1 1 funcref) + (elem (table $table1) (i32.const 0) func $f) (func $f (type $sig) i32.const 42 ) (func (export "wizer.initialize")) (func (export "run") (result i32) i32.const 0 - call_indirect (type $sig) + call_indirect $table1 (type $sig) ) )"#;