From b948b4648468810e2214db0b8cf06581d3e811c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 10 Oct 2022 10:48:52 +0200 Subject: [PATCH 01/13] Added failing testcase for #3197 --- lib/api/src/sys/externals/table.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index ee3a6fba475..bdfa6e5a91b 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -211,3 +211,18 @@ impl<'a> Exportable<'a> for Table { } } } + +#[test] +fn test_table_grow_3197() { + use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; + + const WAT:&str = r#"(module (table (import "env" "table") 100 funcref))"#; + + let mut store = Store::default(); + let module = Module::new(&store, WAT).unwrap(); + let ty = TableType::new(Type::FuncRef, 0, None); + let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap(); + table.grow(&mut store, 100, Value::FuncRef(None)).unwrap(); + let imports = imports! {"env" => {"table" => table}}; + let _instance = Instance::new(&mut store, &module, &imports).unwrap(); +} \ No newline at end of file From 17aec88db86dcf0a6f7bce1c6350304b318a6d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 10 Oct 2022 11:27:00 +0200 Subject: [PATCH 02/13] Update minimum of table when growing table --- lib/api/src/sys/externals/table.rs | 4 ++-- lib/vm/src/table.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index bdfa6e5a91b..32c140c3d6e 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -216,7 +216,7 @@ impl<'a> Exportable<'a> for Table { fn test_table_grow_3197() { use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; - const WAT:&str = r#"(module (table (import "env" "table") 100 funcref))"#; + const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; let mut store = Store::default(); let module = Module::new(&store, WAT).unwrap(); @@ -225,4 +225,4 @@ fn test_table_grow_3197() { table.grow(&mut store, 100, Value::FuncRef(None)).unwrap(); let imports = imports! {"env" => {"table" => table}}; let _instance = Instance::new(&mut store, &module, &imports).unwrap(); -} \ No newline at end of file +} diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index bdc5e5fdbaa..55cea2e0070 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -196,6 +196,7 @@ impl VMTable { self.vec .resize(usize::try_from(new_len).unwrap(), init_value.into()); + self.table.minimum = new_len; // update table definition unsafe { From f4dc64d0c15b389f06607c2317fc89c12a70f771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= <12084016+fschutt@users.noreply.github.com> Date: Tue, 11 Oct 2022 11:48:35 +0200 Subject: [PATCH 03/13] Use `vec.len()` to synchronize table length when growing table --- lib/vm/src/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index 55cea2e0070..aa9c9e92d1f 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -196,7 +196,7 @@ impl VMTable { self.vec .resize(usize::try_from(new_len).unwrap(), init_value.into()); - self.table.minimum = new_len; + self.table.minimum = self.vec.len(); // update table descriptor // update table definition unsafe { From 332b8b1b718117ad10b138f8f0c544447fea530c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 11 Oct 2022 11:51:22 +0200 Subject: [PATCH 04/13] Revert to using new_len --- lib/vm/src/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index aa9c9e92d1f..55cea2e0070 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -196,7 +196,7 @@ impl VMTable { self.vec .resize(usize::try_from(new_len).unwrap(), init_value.into()); - self.table.minimum = self.vec.len(); // update table descriptor + self.table.minimum = new_len; // update table definition unsafe { From 292ec7aaded691b7c74650dc877a0eb3cc129527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 12:36:19 +0200 Subject: [PATCH 05/13] Try using >= as a comparison for checking table sizes --- lib/types/src/types.rs | 2 +- lib/vm/src/table.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/types/src/types.rs b/lib/types/src/types.rs index cf5d07df410..62f500d1da0 100644 --- a/lib/types/src/types.rs +++ b/lib/types/src/types.rs @@ -154,7 +154,7 @@ fn is_table_compatible(exported: &TableType, imported: &TableType) -> bool { } = imported; is_table_element_type_compatible(*exported_ty, *imported_ty) - && imported_minimum <= exported_minimum + && imported_minimum >= exported_minimum && (imported_maximum.is_none() || (!exported_maximum.is_none() && imported_maximum.unwrap() >= exported_maximum.unwrap())) diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index 55cea2e0070..bdc5e5fdbaa 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -196,7 +196,6 @@ impl VMTable { self.vec .resize(usize::try_from(new_len).unwrap(), init_value.into()); - self.table.minimum = new_len; // update table definition unsafe { From 607050641c178fb9740d916ffc88c3bfa0c105f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 14:08:25 +0200 Subject: [PATCH 06/13] Added get_runtime_size to test for runtime-sizes of imports --- lib/api/src/js/export.rs | 7 +++++++ lib/compiler/src/engine/resolver.rs | 11 ++++++++++- lib/types/src/types.rs | 12 ++++++------ lib/vm/src/memory.rs | 5 +++++ lib/vm/src/table.rs | 5 +++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index 0241899019f..4e41f3bbe7c 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -22,6 +22,10 @@ impl VMMemory { Self { memory, ty } } + pub fn get_runtime_size(&self) -> u32 { + self.memory.get_runtime_size() + } + /// Attempts to clone this memory (if its clonable) pub(crate) fn try_clone(&self) -> Option { Some(self.clone()) @@ -56,6 +60,9 @@ impl VMTable { pub(crate) fn new(table: Table, ty: TableType) -> Self { Self { table, ty } } + pub fn get_runtime_size(&self) -> u32 { + self.table.get_runtime_size() + } } #[derive(Clone)] diff --git a/lib/compiler/src/engine/resolver.rs b/lib/compiler/src/engine/resolver.rs index 87fa45f3001..9fac5fc0aec 100644 --- a/lib/compiler/src/engine/resolver.rs +++ b/lib/compiler/src/engine/resolver.rs @@ -48,6 +48,14 @@ fn get_extern_type(context: &StoreObjects, extern_: &VMExtern) -> ExternType { } } +fn get_runtime_size(context: &StoreObjects, extern_: &VMExtern) -> Option { + match extern_ { + VMExtern::Table(t) => Some(t.get(context).get_runtime_size()), + VMExtern::Memory(m) => Some(m.get(context).get_runtime_size()), + _ => None, + } +} + /// This function allows to match all imports of a `ModuleInfo` with concrete definitions provided by /// a `Resolver`. /// @@ -85,7 +93,8 @@ pub fn resolve_imports( )); }; let extern_type = get_extern_type(context, resolved); - if !extern_type.is_compatible_with(&import_extern) { + let runtime_size = get_runtime_size(context, resolved); + if !extern_type.is_compatible_with(&import_extern, runtime_size) { return Err(LinkError::Import( module_name.to_string(), field.to_string(), diff --git a/lib/types/src/types.rs b/lib/types/src/types.rs index 62f500d1da0..cf1b6ba02d8 100644 --- a/lib/types/src/types.rs +++ b/lib/types/src/types.rs @@ -141,7 +141,7 @@ fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> } } -fn is_table_compatible(exported: &TableType, imported: &TableType) -> bool { +fn is_table_compatible(exported: &TableType, imported: &TableType, imported_runtime_size: Option) -> bool { let TableType { ty: exported_ty, minimum: exported_minimum, @@ -154,13 +154,13 @@ fn is_table_compatible(exported: &TableType, imported: &TableType) -> bool { } = imported; is_table_element_type_compatible(*exported_ty, *imported_ty) - && imported_minimum >= exported_minimum + && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum) && (imported_maximum.is_none() || (!exported_maximum.is_none() && imported_maximum.unwrap() >= exported_maximum.unwrap())) } -fn is_memory_compatible(exported: &MemoryType, imported: &MemoryType) -> bool { +fn is_memory_compatible(exported: &MemoryType, imported: &MemoryType, _: Option) -> bool { let MemoryType { minimum: exported_minimum, maximum: exported_maximum, @@ -211,12 +211,12 @@ impl ExternType { (Memory(MemoryType) memory unwrap_memory) } /// Check if two externs are compatible - pub fn is_compatible_with(&self, other: &Self) -> bool { + pub fn is_compatible_with(&self, other: &Self, runtime_size: Option) -> bool { match (self, other) { (Self::Function(a), Self::Function(b)) => a == b, (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b), - (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b), - (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b), + (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size), + (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size), // The rest of possibilities, are not compatible _ => false, } diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index f8b80d2cee4..99474aa3b2d 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -361,6 +361,11 @@ impl VMMemory { Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?))) } + /// Returns the size of the allocated memory block + pub fn get_runtime_size(&self) -> u32 { + unsafe { self.0.vmmemory().as_ref() }.current_length as u32 + } + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. /// /// This creates a `Memory` with metadata owned by a VM, pointed to by diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index bdc5e5fdbaa..b29d8c883c4 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -88,6 +88,11 @@ impl VMTable { unsafe { Self::new_inner(table, style, None) } } + /// Returns the size of the table + pub fn get_runtime_size(&self) -> u32 { + self.vec.len() as u32 + } + /// Create a new linear table instance with specified minimum and maximum number of elements. /// /// This creates a `Table` with metadata owned by a VM, pointed to by From ad1f4fea0512e9f98362286ba68a9a745c648fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 14:12:52 +0200 Subject: [PATCH 07/13] cargo fmt --- lib/types/src/types.rs | 6 +++++- lib/vm/src/memory.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/types/src/types.rs b/lib/types/src/types.rs index cf1b6ba02d8..47732fbde29 100644 --- a/lib/types/src/types.rs +++ b/lib/types/src/types.rs @@ -141,7 +141,11 @@ fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> } } -fn is_table_compatible(exported: &TableType, imported: &TableType, imported_runtime_size: Option) -> bool { +fn is_table_compatible( + exported: &TableType, + imported: &TableType, + imported_runtime_size: Option, +) -> bool { let TableType { ty: exported_ty, minimum: exported_minimum, diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 99474aa3b2d..c7e86c47466 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -365,7 +365,7 @@ impl VMMemory { pub fn get_runtime_size(&self) -> u32 { unsafe { self.0.vmmemory().as_ref() }.current_length as u32 } - + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. /// /// This creates a `Memory` with metadata owned by a VM, pointed to by From b645800ae3b18463f4b2be1562ad9ef5337be41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 14:39:24 +0200 Subject: [PATCH 08/13] Fix runtime size for Memory --- lib/types/src/types.rs | 8 ++++++-- lib/vm/src/memory.rs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/types/src/types.rs b/lib/types/src/types.rs index 47732fbde29..ec26e089f07 100644 --- a/lib/types/src/types.rs +++ b/lib/types/src/types.rs @@ -164,7 +164,11 @@ fn is_table_compatible( && imported_maximum.unwrap() >= exported_maximum.unwrap())) } -fn is_memory_compatible(exported: &MemoryType, imported: &MemoryType, _: Option) -> bool { +fn is_memory_compatible( + exported: &MemoryType, + imported: &MemoryType, + imported_runtime_size: Option, +) -> bool { let MemoryType { minimum: exported_minimum, maximum: exported_maximum, @@ -176,7 +180,7 @@ fn is_memory_compatible(exported: &MemoryType, imported: &MemoryType, _: Option< shared: imported_shared, } = imported; - imported_minimum <= exported_minimum + imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0) && (imported_maximum.is_none() || (!exported_maximum.is_none() && imported_maximum.unwrap() >= exported_maximum.unwrap())) diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index c7e86c47466..31133dc66d5 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -363,7 +363,7 @@ impl VMMemory { /// Returns the size of the allocated memory block pub fn get_runtime_size(&self) -> u32 { - unsafe { self.0.vmmemory().as_ref() }.current_length as u32 + self.0.size().0 } /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. From 638e90e56e9a76df46cb1897cef27fbc1317ffd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 15:45:10 +0200 Subject: [PATCH 09/13] Add get_runtime_size for JS --- Cargo.lock | 13 +++++++++++++ lib/api/Cargo.toml | 3 +++ lib/api/src/js/export.rs | 21 ++++++++++++++++++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4aa7427890..823efc60a18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2315,6 +2315,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.7" @@ -3070,6 +3081,8 @@ dependencies = [ "js-sys", "macro-wasmer-universal-test", "more-asserts", + "serde", + "serde-wasm-bindgen", "target-lexicon 0.12.4", "tempfile", "thiserror", diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 4e5e275b070..ac257346104 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -68,6 +68,9 @@ wasmer-derive = { path = "../derive", version = "=3.0.0-beta.2" } # - Optional dependencies for `js`. wasmparser = { version = "0.83", default-features = false, optional = true } hashbrown = { version = "0.11", optional = true } +serde-wasm-bindgen = { version = "0.4.5" } +serde = { version = "1.0", features = ["derive"] } + # - Development Dependencies for `js`. [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wat = "1.0" diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index 4e41f3bbe7c..a24ab273360 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -3,9 +3,10 @@ use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle}; use crate::js::wasm_bindgen_polyfill::Global; use js_sys::Function; use js_sys::WebAssembly::{Memory, Table}; +use serde::{Deserialize, Serialize}; use std::fmt; use wasm_bindgen::{JsCast, JsValue}; -use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType}; +use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType, WASM_PAGE_SIZE}; /// Represents linear memory that is managed by the javascript runtime #[derive(Clone, Debug, PartialEq)] @@ -17,13 +18,27 @@ pub struct VMMemory { unsafe impl Send for VMMemory {} unsafe impl Sync for VMMemory {} +#[derive(Serialize, Deserialize)] +struct DummyBuffer { + #[serde(rename = "byteLength")] + byte_length: u32, +} + impl VMMemory { pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self { Self { memory, ty } } + /// Returns the size of the memory buffer in pages pub fn get_runtime_size(&self) -> u32 { - self.memory.get_runtime_size() + let dummy: DummyBuffer = match serde_wasm_bindgen::from_value(self.memory.buffer()) { + Ok(o) => o, + Err(_) => return 0, + }; + if dummy.byte_length == 0 { + return 0; + } + dummy.byte_length / 65536 } /// Attempts to clone this memory (if its clonable) @@ -61,7 +76,7 @@ impl VMTable { Self { table, ty } } pub fn get_runtime_size(&self) -> u32 { - self.table.get_runtime_size() + self.table.length() } } From e6f6e6047af39456c6a994c6b9da18c3a96e0652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 15:59:17 +0200 Subject: [PATCH 10/13] Fix wrong doc comment --- lib/api/src/js/export.rs | 2 +- lib/vm/src/memory.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index a24ab273360..fdbd374cc0c 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -38,7 +38,7 @@ impl VMMemory { if dummy.byte_length == 0 { return 0; } - dummy.byte_length / 65536 + dummy.byte_length / WASM_PAGE_SIZE } /// Attempts to clone this memory (if its clonable) diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 31133dc66d5..117a01a4113 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -361,7 +361,7 @@ impl VMMemory { Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?))) } - /// Returns the size of the allocated memory block + /// Returns the number of pages in the allocated memory block pub fn get_runtime_size(&self) -> u32 { self.0.size().0 } From 8be77c91ffa0cf558e8962b38e15666e9f3cfa75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 16:03:30 +0200 Subject: [PATCH 11/13] Fix WASM_PAGE_SIZE --- lib/api/src/js/export.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index fdbd374cc0c..a8cb689ed02 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -38,7 +38,7 @@ impl VMMemory { if dummy.byte_length == 0 { return 0; } - dummy.byte_length / WASM_PAGE_SIZE + dummy.byte_length / WASM_PAGE_SIZE as u32 } /// Attempts to clone this memory (if its clonable) From 8a0ddaee6da20d0ce7169f9f74b4b5f727c0b77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= <12084016+fschutt@users.noreply.github.com> Date: Fri, 14 Oct 2022 16:04:32 +0200 Subject: [PATCH 12/13] Add link to PR Co-authored-by: Michael Bryan --- lib/api/src/sys/externals/table.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 32c140c3d6e..6fc8ca15371 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -212,8 +212,9 @@ impl<'a> Exportable<'a> for Table { } } +/// Check the example from . #[test] -fn test_table_grow_3197() { +fn test_table_grow_issue_3197() { use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; From 3468a6c69772d139280682ac77d6926917768f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 16:25:43 +0200 Subject: [PATCH 13/13] Add comment explaining the unit test --- lib/api/src/sys/externals/table.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs index 6fc8ca15371..727c9063239 100644 --- a/lib/api/src/sys/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -219,11 +219,14 @@ fn test_table_grow_issue_3197() { const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; + // Tests that the table type of `table` is compatible with the export in the WAT + // This tests that `wasmer_types::types::is_table_compatible` works as expected. let mut store = Store::default(); let module = Module::new(&store, WAT).unwrap(); let ty = TableType::new(Type::FuncRef, 0, None); let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap(); table.grow(&mut store, 100, Value::FuncRef(None)).unwrap(); + assert_eq!(table.ty(&store).minimum, 0); let imports = imports! {"env" => {"table" => table}}; let _instance = Instance::new(&mut store, &module, &imports).unwrap(); }