190ac295eSAlex Crichton use super::{ErrorExt, skip_pooling_allocator_tests};
2e71ccbf9SPeter Huene use wasmtime::*;
3e71ccbf9SPeter Huene
4e71ccbf9SPeter Huene #[test]
successful_instantiation() -> Result<()>5e71ccbf9SPeter Huene fn successful_instantiation() -> Result<()> {
6a34427a3SNick Fitzgerald let pool = crate::small_pool_config();
7e71ccbf9SPeter Huene let mut config = Config::new();
8c0f03d08SAlex Crichton config.allocation_strategy(pool);
948d5338bSAlex Crichton config.memory_guard_size(0);
107a28a5b9SAlex Crichton config.memory_reservation(1 << 16);
11e71ccbf9SPeter Huene
1254c07d8fSPeter Huene let engine = Engine::new(&config)?;
13e71ccbf9SPeter Huene let module = Module::new(&engine, r#"(module (memory 1) (table 10 funcref))"#)?;
14e71ccbf9SPeter Huene
15e71ccbf9SPeter Huene // Module should instantiate
167a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
177a1b7cdfSAlex Crichton Instance::new(&mut store, &module, &[])?;
18e71ccbf9SPeter Huene
19e71ccbf9SPeter Huene Ok(())
20e71ccbf9SPeter Huene }
21e71ccbf9SPeter Huene
22e71ccbf9SPeter Huene #[test]
23c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
memory_limit() -> Result<()>24e71ccbf9SPeter Huene fn memory_limit() -> Result<()> {
25a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
26906ea017SAlex Crichton pool.max_memory_size(3 << 16);
27e71ccbf9SPeter Huene let mut config = Config::new();
28c0f03d08SAlex Crichton config.allocation_strategy(pool);
2948d5338bSAlex Crichton config.memory_guard_size(1 << 16);
307a28a5b9SAlex Crichton config.memory_reservation(3 << 16);
3115bb0c69SAlex Crichton config.wasm_multi_memory(true);
32e71ccbf9SPeter Huene
3354c07d8fSPeter Huene let engine = Engine::new(&config)?;
34e71ccbf9SPeter Huene
3515bb0c69SAlex Crichton // Module should fail to instantiate because it has too many memories
3615bb0c69SAlex Crichton match Module::new(&engine, r#"(module (memory 1) (memory 1))"#) {
3715bb0c69SAlex Crichton Ok(_) => panic!("module instantiation should fail"),
3842bb677fSAlex Crichton Err(e) => {
3942bb677fSAlex Crichton e.assert_contains("defined memories count of 2 exceeds the per-instance limit of 1")
4042bb677fSAlex Crichton }
4115bb0c69SAlex Crichton }
4215bb0c69SAlex Crichton
4315bb0c69SAlex Crichton // Module should fail to instantiate because the minimum is greater than
4415bb0c69SAlex Crichton // the configured limit
4515bb0c69SAlex Crichton match Module::new(&engine, r#"(module (memory 4))"#) {
4615bb0c69SAlex Crichton Ok(_) => panic!("module instantiation should fail"),
47c22b3cb9SNick Fitzgerald Err(e) => {
4842bb677fSAlex Crichton e.assert_contains(
49c22b3cb9SNick Fitzgerald "memory index 0 is unsupported in this pooling allocator \
50c22b3cb9SNick Fitzgerald configuration",
51c22b3cb9SNick Fitzgerald );
52c22b3cb9SNick Fitzgerald e.assert_contains(
53c22b3cb9SNick Fitzgerald "memory has a minimum byte size of 262144 which exceeds \
54c22b3cb9SNick Fitzgerald the limit of 0x30000 bytes",
55c22b3cb9SNick Fitzgerald );
56c22b3cb9SNick Fitzgerald }
57e71ccbf9SPeter Huene }
58e71ccbf9SPeter Huene
59e71ccbf9SPeter Huene let module = Module::new(
60e71ccbf9SPeter Huene &engine,
61e71ccbf9SPeter Huene r#"(module (memory (export "m") 0) (func (export "f") (result i32) (memory.grow (i32.const 1))))"#,
62e71ccbf9SPeter Huene )?;
63e71ccbf9SPeter Huene
64e71ccbf9SPeter Huene // Instantiate the module and grow the memory via the `f` function
65e71ccbf9SPeter Huene {
667a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
677a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
68b0939f66SAlex Crichton let f = instance.get_typed_func::<(), i32>(&mut store, "f")?;
69e71ccbf9SPeter Huene
707a1b7cdfSAlex Crichton assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 0);
717a1b7cdfSAlex Crichton assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 1);
727a1b7cdfSAlex Crichton assert_eq!(f.call(&mut store, ()).expect("function should not trap"), 2);
737a1b7cdfSAlex Crichton assert_eq!(
747a1b7cdfSAlex Crichton f.call(&mut store, ()).expect("function should not trap"),
757a1b7cdfSAlex Crichton -1
767a1b7cdfSAlex Crichton );
777a1b7cdfSAlex Crichton assert_eq!(
787a1b7cdfSAlex Crichton f.call(&mut store, ()).expect("function should not trap"),
797a1b7cdfSAlex Crichton -1
807a1b7cdfSAlex Crichton );
81e71ccbf9SPeter Huene }
82e71ccbf9SPeter Huene
83e71ccbf9SPeter Huene // Instantiate the module and grow the memory via the Wasmtime API
847a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
857a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
86e71ccbf9SPeter Huene
877a1b7cdfSAlex Crichton let memory = instance.get_memory(&mut store, "m").unwrap();
887a1b7cdfSAlex Crichton assert_eq!(memory.size(&store), 0);
897a1b7cdfSAlex Crichton assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 0);
907a1b7cdfSAlex Crichton assert_eq!(memory.size(&store), 1);
917a1b7cdfSAlex Crichton assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 1);
927a1b7cdfSAlex Crichton assert_eq!(memory.size(&store), 2);
937a1b7cdfSAlex Crichton assert_eq!(memory.grow(&mut store, 1).expect("memory should grow"), 2);
947a1b7cdfSAlex Crichton assert_eq!(memory.size(&store), 3);
957a1b7cdfSAlex Crichton assert!(memory.grow(&mut store, 1).is_err());
96e71ccbf9SPeter Huene
97e71ccbf9SPeter Huene Ok(())
98e71ccbf9SPeter Huene }
99e71ccbf9SPeter Huene
100e71ccbf9SPeter Huene #[test]
memory_init() -> Result<()>101e71ccbf9SPeter Huene fn memory_init() -> Result<()> {
102a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
103906ea017SAlex Crichton pool.max_memory_size(2 << 16).table_elements(0);
104e71ccbf9SPeter Huene let mut config = Config::new();
105c0f03d08SAlex Crichton config.allocation_strategy(pool);
106e71ccbf9SPeter Huene
10754c07d8fSPeter Huene let engine = Engine::new(&config)?;
108e71ccbf9SPeter Huene
109e71ccbf9SPeter Huene let module = Module::new(
110e71ccbf9SPeter Huene &engine,
111c0bb341dSAlex Crichton r#"
112c0bb341dSAlex Crichton (module
113c0bb341dSAlex Crichton (memory (export "m") 2)
114c0bb341dSAlex Crichton (data (i32.const 65530) "this data spans multiple pages")
115c0bb341dSAlex Crichton (data (i32.const 10) "hello world")
116c0bb341dSAlex Crichton )
117c0bb341dSAlex Crichton "#,
118e71ccbf9SPeter Huene )?;
119e71ccbf9SPeter Huene
1207a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
1217a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
1227a1b7cdfSAlex Crichton let memory = instance.get_memory(&mut store, "m").unwrap();
123e71ccbf9SPeter Huene
124e71ccbf9SPeter Huene assert_eq!(
1257a1b7cdfSAlex Crichton &memory.data(&store)[65530..65560],
126e71ccbf9SPeter Huene b"this data spans multiple pages"
127e71ccbf9SPeter Huene );
1287a1b7cdfSAlex Crichton assert_eq!(&memory.data(&store)[10..21], b"hello world");
129e71ccbf9SPeter Huene
130e71ccbf9SPeter Huene Ok(())
131e71ccbf9SPeter Huene }
132e71ccbf9SPeter Huene
133e71ccbf9SPeter Huene #[test]
134c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
memory_guard_page_trap() -> Result<()>135e71ccbf9SPeter Huene fn memory_guard_page_trap() -> Result<()> {
136a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
137906ea017SAlex Crichton pool.max_memory_size(2 << 16).table_elements(0);
138e71ccbf9SPeter Huene let mut config = Config::new();
139c0f03d08SAlex Crichton config.allocation_strategy(pool);
140e71ccbf9SPeter Huene
14154c07d8fSPeter Huene let engine = Engine::new(&config)?;
142e71ccbf9SPeter Huene
143e71ccbf9SPeter Huene let module = Module::new(
144e71ccbf9SPeter Huene &engine,
145c0bb341dSAlex Crichton r#"
146c0bb341dSAlex Crichton (module
147c0bb341dSAlex Crichton (memory (export "m") 0)
148c0bb341dSAlex Crichton (func (export "f") (param i32) local.get 0 i32.load drop)
149c0bb341dSAlex Crichton )
150c0bb341dSAlex Crichton "#,
151e71ccbf9SPeter Huene )?;
152e71ccbf9SPeter Huene
153e71ccbf9SPeter Huene // Instantiate the module and check for out of bounds trap
154e71ccbf9SPeter Huene for _ in 0..10 {
1557a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
1567a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
1577a1b7cdfSAlex Crichton let m = instance.get_memory(&mut store, "m").unwrap();
158b0939f66SAlex Crichton let f = instance.get_typed_func::<i32, ()>(&mut store, "f")?;
159e71ccbf9SPeter Huene
1602afaac51SAlex Crichton let trap = f
1612afaac51SAlex Crichton .call(&mut store, 0)
1622afaac51SAlex Crichton .expect_err("function should trap")
1632afaac51SAlex Crichton .downcast::<Trap>()?;
1642afaac51SAlex Crichton assert_eq!(trap, Trap::MemoryOutOfBounds);
165e71ccbf9SPeter Huene
1662afaac51SAlex Crichton let trap = f
1672afaac51SAlex Crichton .call(&mut store, 1)
1682afaac51SAlex Crichton .expect_err("function should trap")
1692afaac51SAlex Crichton .downcast::<Trap>()?;
1702afaac51SAlex Crichton assert_eq!(trap, Trap::MemoryOutOfBounds);
171e71ccbf9SPeter Huene
1727a1b7cdfSAlex Crichton m.grow(&mut store, 1).expect("memory should grow");
1737a1b7cdfSAlex Crichton f.call(&mut store, 0).expect("function should not trap");
174e71ccbf9SPeter Huene
1752afaac51SAlex Crichton let trap = f
1762afaac51SAlex Crichton .call(&mut store, 65536)
1772afaac51SAlex Crichton .expect_err("function should trap")
1782afaac51SAlex Crichton .downcast::<Trap>()?;
1792afaac51SAlex Crichton assert_eq!(trap, Trap::MemoryOutOfBounds);
180e71ccbf9SPeter Huene
1812afaac51SAlex Crichton let trap = f
1822afaac51SAlex Crichton .call(&mut store, 65537)
1832afaac51SAlex Crichton .expect_err("function should trap")
1842afaac51SAlex Crichton .downcast::<Trap>()?;
1852afaac51SAlex Crichton assert_eq!(trap, Trap::MemoryOutOfBounds);
186e71ccbf9SPeter Huene
1877a1b7cdfSAlex Crichton m.grow(&mut store, 1).expect("memory should grow");
1887a1b7cdfSAlex Crichton f.call(&mut store, 65536).expect("function should not trap");
189e71ccbf9SPeter Huene
1907a1b7cdfSAlex Crichton m.grow(&mut store, 1)
1917a1b7cdfSAlex Crichton .expect_err("memory should be at the limit");
192e71ccbf9SPeter Huene }
193e71ccbf9SPeter Huene
194e71ccbf9SPeter Huene Ok(())
195e71ccbf9SPeter Huene }
196e71ccbf9SPeter Huene
197e71ccbf9SPeter Huene #[test]
memory_zeroed() -> Result<()>198e71ccbf9SPeter Huene fn memory_zeroed() -> Result<()> {
199cb937262SAnton Kirilov if skip_pooling_allocator_tests() {
200cb937262SAnton Kirilov return Ok(());
201cb937262SAnton Kirilov }
202cb937262SAnton Kirilov
203a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
204906ea017SAlex Crichton pool.max_memory_size(1 << 16).table_elements(0);
205e71ccbf9SPeter Huene let mut config = Config::new();
206c0f03d08SAlex Crichton config.allocation_strategy(pool);
20748d5338bSAlex Crichton config.memory_guard_size(0);
2087a28a5b9SAlex Crichton config.memory_reservation(1 << 16);
209e71ccbf9SPeter Huene
21054c07d8fSPeter Huene let engine = Engine::new(&config)?;
211e71ccbf9SPeter Huene
212e71ccbf9SPeter Huene let module = Module::new(&engine, r#"(module (memory (export "m") 1))"#)?;
213e71ccbf9SPeter Huene
214e71ccbf9SPeter Huene // Instantiate the module repeatedly after writing data to the entire memory
215e71ccbf9SPeter Huene for _ in 0..10 {
2167a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
2177a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
2187a1b7cdfSAlex Crichton let memory = instance.get_memory(&mut store, "m").unwrap();
219e71ccbf9SPeter Huene
2207a1b7cdfSAlex Crichton assert_eq!(memory.size(&store,), 1);
2217a1b7cdfSAlex Crichton assert_eq!(memory.data_size(&store), 65536);
222e71ccbf9SPeter Huene
2237a1b7cdfSAlex Crichton let ptr = memory.data_mut(&mut store).as_mut_ptr();
224e71ccbf9SPeter Huene
225e71ccbf9SPeter Huene unsafe {
226e71ccbf9SPeter Huene for i in 0..8192 {
227e71ccbf9SPeter Huene assert_eq!(*ptr.cast::<u64>().offset(i), 0);
228e71ccbf9SPeter Huene }
2297a1b7cdfSAlex Crichton std::ptr::write_bytes(ptr, 0xFE, memory.data_size(&store));
230e71ccbf9SPeter Huene }
231e71ccbf9SPeter Huene }
232e71ccbf9SPeter Huene
233e71ccbf9SPeter Huene Ok(())
234e71ccbf9SPeter Huene }
235e71ccbf9SPeter Huene
236e71ccbf9SPeter Huene #[test]
237c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
table_limit() -> Result<()>238e71ccbf9SPeter Huene fn table_limit() -> Result<()> {
239df69b9a7SLinwei Shang const TABLE_ELEMENTS: usize = 10;
240a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
241a34427a3SNick Fitzgerald pool.table_elements(TABLE_ELEMENTS);
242e71ccbf9SPeter Huene let mut config = Config::new();
243c0f03d08SAlex Crichton config.allocation_strategy(pool);
24448d5338bSAlex Crichton config.memory_guard_size(0);
2457a28a5b9SAlex Crichton config.memory_reservation(1 << 16);
246e71ccbf9SPeter Huene
24754c07d8fSPeter Huene let engine = Engine::new(&config)?;
248e71ccbf9SPeter Huene
24915bb0c69SAlex Crichton // Module should fail to instantiate because it has too many tables
25015bb0c69SAlex Crichton match Module::new(&engine, r#"(module (table 1 funcref) (table 1 funcref))"#) {
25115bb0c69SAlex Crichton Ok(_) => panic!("module compilation should fail"),
25242bb677fSAlex Crichton Err(e) => {
25342bb677fSAlex Crichton e.assert_contains("defined tables count of 2 exceeds the per-instance limit of 1")
25442bb677fSAlex Crichton }
25515bb0c69SAlex Crichton }
25615bb0c69SAlex Crichton
25715bb0c69SAlex Crichton // Module should fail to instantiate because the minimum is greater than
25815bb0c69SAlex Crichton // the configured limit
259e71ccbf9SPeter Huene match Module::new(&engine, r#"(module (table 31 funcref))"#) {
260e71ccbf9SPeter Huene Ok(_) => panic!("module compilation should fail"),
26142bb677fSAlex Crichton Err(e) => e.assert_contains(
26215bb0c69SAlex Crichton "table index 0 has a minimum element size of 31 which exceeds the limit of 10",
263a464465eSPeter Huene ),
264e71ccbf9SPeter Huene }
265e71ccbf9SPeter Huene
266e71ccbf9SPeter Huene let module = Module::new(
267e71ccbf9SPeter Huene &engine,
268e71ccbf9SPeter Huene r#"(module (table (export "t") 0 funcref) (func (export "f") (result i32) (table.grow (ref.null func) (i32.const 1))))"#,
269e71ccbf9SPeter Huene )?;
270e71ccbf9SPeter Huene
271e71ccbf9SPeter Huene // Instantiate the module and grow the table via the `f` function
272e71ccbf9SPeter Huene {
2737a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
2747a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
275b0939f66SAlex Crichton let f = instance.get_typed_func::<(), i32>(&mut store, "f")?;
276e71ccbf9SPeter Huene
277e71ccbf9SPeter Huene for i in 0..TABLE_ELEMENTS {
2787a1b7cdfSAlex Crichton assert_eq!(
2797a1b7cdfSAlex Crichton f.call(&mut store, ()).expect("function should not trap"),
2807a1b7cdfSAlex Crichton i as i32
2817a1b7cdfSAlex Crichton );
282e71ccbf9SPeter Huene }
283e71ccbf9SPeter Huene
2847a1b7cdfSAlex Crichton assert_eq!(
2857a1b7cdfSAlex Crichton f.call(&mut store, ()).expect("function should not trap"),
2867a1b7cdfSAlex Crichton -1
2877a1b7cdfSAlex Crichton );
2887a1b7cdfSAlex Crichton assert_eq!(
2897a1b7cdfSAlex Crichton f.call(&mut store, ()).expect("function should not trap"),
2907a1b7cdfSAlex Crichton -1
2917a1b7cdfSAlex Crichton );
292e71ccbf9SPeter Huene }
293e71ccbf9SPeter Huene
294e71ccbf9SPeter Huene // Instantiate the module and grow the table via the Wasmtime API
2957a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
2967a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
297e71ccbf9SPeter Huene
2987a1b7cdfSAlex Crichton let table = instance.get_table(&mut store, "t").unwrap();
299e71ccbf9SPeter Huene
300e71ccbf9SPeter Huene for i in 0..TABLE_ELEMENTS {
301df69b9a7SLinwei Shang assert_eq!(table.size(&store), i as u64);
302e71ccbf9SPeter Huene assert_eq!(
303e71ccbf9SPeter Huene table
304ff93bce0SNick Fitzgerald .grow(&mut store, 1, Ref::Func(None))
305e71ccbf9SPeter Huene .expect("table should grow"),
306df69b9a7SLinwei Shang i as u64
307e71ccbf9SPeter Huene );
308e71ccbf9SPeter Huene }
309e71ccbf9SPeter Huene
310df69b9a7SLinwei Shang assert_eq!(table.size(&store), TABLE_ELEMENTS as u64);
311ff93bce0SNick Fitzgerald assert!(table.grow(&mut store, 1, Ref::Func(None)).is_err());
312e71ccbf9SPeter Huene
313e71ccbf9SPeter Huene Ok(())
314e71ccbf9SPeter Huene }
315e71ccbf9SPeter Huene
316e71ccbf9SPeter Huene #[test]
317c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
table_init() -> Result<()>318e71ccbf9SPeter Huene fn table_init() -> Result<()> {
319a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
320906ea017SAlex Crichton pool.max_memory_size(0).table_elements(6);
321e71ccbf9SPeter Huene let mut config = Config::new();
322c0f03d08SAlex Crichton config.allocation_strategy(pool);
323e71ccbf9SPeter Huene
32454c07d8fSPeter Huene let engine = Engine::new(&config)?;
325e71ccbf9SPeter Huene
326e71ccbf9SPeter Huene let module = Module::new(
327e71ccbf9SPeter Huene &engine,
328c0bb341dSAlex Crichton r#"
329c0bb341dSAlex Crichton (module
330c0bb341dSAlex Crichton (table (export "t") 6 funcref)
331c0bb341dSAlex Crichton (elem (i32.const 1) 1 2 3 4)
332c0bb341dSAlex Crichton (elem (i32.const 0) 0)
333c0bb341dSAlex Crichton (func)
334c0bb341dSAlex Crichton (func (param i32))
335c0bb341dSAlex Crichton (func (param i32 i32))
336c0bb341dSAlex Crichton (func (param i32 i32 i32))
337c0bb341dSAlex Crichton (func (param i32 i32 i32 i32))
338c0bb341dSAlex Crichton )
339c0bb341dSAlex Crichton "#,
340e71ccbf9SPeter Huene )?;
341e71ccbf9SPeter Huene
3427a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
3437a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
3447a1b7cdfSAlex Crichton let table = instance.get_table(&mut store, "t").unwrap();
345e71ccbf9SPeter Huene
346e71ccbf9SPeter Huene for i in 0..5 {
3477a1b7cdfSAlex Crichton let v = table.get(&mut store, i).expect("table should have entry");
348e71ccbf9SPeter Huene let f = v
349ff93bce0SNick Fitzgerald .as_func()
350e71ccbf9SPeter Huene .expect("expected funcref")
351e71ccbf9SPeter Huene .expect("expected non-null value");
3527a1b7cdfSAlex Crichton assert_eq!(f.ty(&store).params().len(), i as usize);
353e71ccbf9SPeter Huene }
354e71ccbf9SPeter Huene
355e71ccbf9SPeter Huene assert!(
356e71ccbf9SPeter Huene table
3577a1b7cdfSAlex Crichton .get(&mut store, 5)
358e71ccbf9SPeter Huene .expect("table should have entry")
359ff93bce0SNick Fitzgerald .as_func()
360e71ccbf9SPeter Huene .expect("expected funcref")
361e71ccbf9SPeter Huene .is_none(),
362e71ccbf9SPeter Huene "funcref should be null"
363e71ccbf9SPeter Huene );
364e71ccbf9SPeter Huene
365e71ccbf9SPeter Huene Ok(())
366e71ccbf9SPeter Huene }
367e71ccbf9SPeter Huene
368e71ccbf9SPeter Huene #[test]
table_zeroed() -> Result<()>369e71ccbf9SPeter Huene fn table_zeroed() -> Result<()> {
370cb937262SAnton Kirilov if skip_pooling_allocator_tests() {
371cb937262SAnton Kirilov return Ok(());
372cb937262SAnton Kirilov }
373cb937262SAnton Kirilov
374a34427a3SNick Fitzgerald let pool = crate::small_pool_config();
375e71ccbf9SPeter Huene let mut config = Config::new();
376c0f03d08SAlex Crichton config.allocation_strategy(pool);
37748d5338bSAlex Crichton config.memory_guard_size(0);
3787a28a5b9SAlex Crichton config.memory_reservation(1 << 16);
379e71ccbf9SPeter Huene
38054c07d8fSPeter Huene let engine = Engine::new(&config)?;
381e71ccbf9SPeter Huene
382e71ccbf9SPeter Huene let module = Module::new(&engine, r#"(module (table (export "t") 10 funcref))"#)?;
383e71ccbf9SPeter Huene
384e71ccbf9SPeter Huene // Instantiate the module repeatedly after filling table elements
385e71ccbf9SPeter Huene for _ in 0..10 {
3867a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
3877a1b7cdfSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
3887a1b7cdfSAlex Crichton let table = instance.get_table(&mut store, "t").unwrap();
3897a1b7cdfSAlex Crichton let f = Func::wrap(&mut store, || {});
390e71ccbf9SPeter Huene
3917a1b7cdfSAlex Crichton assert_eq!(table.size(&store), 10);
392e71ccbf9SPeter Huene
393e71ccbf9SPeter Huene for i in 0..10 {
3947a1b7cdfSAlex Crichton match table.get(&mut store, i).unwrap() {
395ff93bce0SNick Fitzgerald Ref::Func(r) => assert!(r.is_none()),
396e71ccbf9SPeter Huene _ => panic!("expected a funcref"),
397e71ccbf9SPeter Huene }
398a0442ea0SHamir Mahal table.set(&mut store, i, Ref::Func(Some(f))).unwrap();
399e71ccbf9SPeter Huene }
400e71ccbf9SPeter Huene }
401e71ccbf9SPeter Huene
402e71ccbf9SPeter Huene Ok(())
403e71ccbf9SPeter Huene }
404e71ccbf9SPeter Huene
405e71ccbf9SPeter Huene #[test]
total_core_instances_limit() -> Result<()>406a34427a3SNick Fitzgerald fn total_core_instances_limit() -> Result<()> {
407e71ccbf9SPeter Huene const INSTANCE_LIMIT: u32 = 10;
408a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
409a34427a3SNick Fitzgerald pool.total_core_instances(INSTANCE_LIMIT);
410e71ccbf9SPeter Huene let mut config = Config::new();
411c0f03d08SAlex Crichton config.allocation_strategy(pool);
41248d5338bSAlex Crichton config.memory_guard_size(0);
4137a28a5b9SAlex Crichton config.memory_reservation(1 << 16);
414e71ccbf9SPeter Huene
41554c07d8fSPeter Huene let engine = Engine::new(&config)?;
416e71ccbf9SPeter Huene let module = Module::new(&engine, r#"(module)"#)?;
417e71ccbf9SPeter Huene
418e71ccbf9SPeter Huene // Instantiate to the limit
419e71ccbf9SPeter Huene {
4207a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
421e71ccbf9SPeter Huene
422e71ccbf9SPeter Huene for _ in 0..INSTANCE_LIMIT {
4237a1b7cdfSAlex Crichton Instance::new(&mut store, &module, &[])?;
424e71ccbf9SPeter Huene }
425e71ccbf9SPeter Huene
4267a1b7cdfSAlex Crichton match Instance::new(&mut store, &module, &[]) {
427e71ccbf9SPeter Huene Ok(_) => panic!("instantiation should fail"),
428e1f8b9b7SNick Fitzgerald Err(e) => assert!(e.is::<PoolConcurrencyLimitError>()),
429e71ccbf9SPeter Huene }
430e71ccbf9SPeter Huene }
431e71ccbf9SPeter Huene
432e71ccbf9SPeter Huene // With the above store dropped, ensure instantiations can be made
433e71ccbf9SPeter Huene
4347a1b7cdfSAlex Crichton let mut store = Store::new(&engine, ());
435e71ccbf9SPeter Huene
436e71ccbf9SPeter Huene for _ in 0..INSTANCE_LIMIT {
4377a1b7cdfSAlex Crichton Instance::new(&mut store, &module, &[])?;
438e71ccbf9SPeter Huene }
439e71ccbf9SPeter Huene
440e71ccbf9SPeter Huene Ok(())
441e71ccbf9SPeter Huene }
442da5c82b7SAlex Crichton
443da5c82b7SAlex Crichton #[test]
preserve_data_segments() -> Result<()>444da5c82b7SAlex Crichton fn preserve_data_segments() -> Result<()> {
445a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
446a34427a3SNick Fitzgerald pool.total_memories(2);
447da5c82b7SAlex Crichton let mut config = Config::new();
448c0f03d08SAlex Crichton config.allocation_strategy(pool);
449da5c82b7SAlex Crichton let engine = Engine::new(&config)?;
450da5c82b7SAlex Crichton let m = Module::new(
451da5c82b7SAlex Crichton &engine,
452da5c82b7SAlex Crichton r#"
453da5c82b7SAlex Crichton (module
454da5c82b7SAlex Crichton (memory (export "mem") 1 1)
455da5c82b7SAlex Crichton (data (i32.const 0) "foo"))
456da5c82b7SAlex Crichton "#,
457da5c82b7SAlex Crichton )?;
458da5c82b7SAlex Crichton let mut store = Store::new(&engine, ());
459da5c82b7SAlex Crichton let i = Instance::new(&mut store, &m, &[])?;
460da5c82b7SAlex Crichton
461da5c82b7SAlex Crichton // Drop the module. This should *not* drop the actual data referenced by the
4623f3afb45SAlex Crichton // module.
463da5c82b7SAlex Crichton drop(m);
464da5c82b7SAlex Crichton
465da5c82b7SAlex Crichton // Spray some stuff on the heap. If wasm data lived on the heap this should
466da5c82b7SAlex Crichton // paper over things and help us catch use-after-free here if it would
467da5c82b7SAlex Crichton // otherwise happen.
468c0bb341dSAlex Crichton if !cfg!(miri) {
469da5c82b7SAlex Crichton let mut strings = Vec::new();
470da5c82b7SAlex Crichton for _ in 0..1000 {
471da5c82b7SAlex Crichton let mut string = String::new();
472da5c82b7SAlex Crichton for _ in 0..1000 {
473da5c82b7SAlex Crichton string.push('g');
474da5c82b7SAlex Crichton }
475da5c82b7SAlex Crichton strings.push(string);
476da5c82b7SAlex Crichton }
477da5c82b7SAlex Crichton drop(strings);
478c0bb341dSAlex Crichton }
479da5c82b7SAlex Crichton
480da5c82b7SAlex Crichton let mem = i.get_memory(&mut store, "mem").unwrap();
481da5c82b7SAlex Crichton
4823f3afb45SAlex Crichton // Hopefully it's still `foo`!
483da5c82b7SAlex Crichton assert!(mem.data(&store).starts_with(b"foo"));
484da5c82b7SAlex Crichton
485da5c82b7SAlex Crichton Ok(())
486da5c82b7SAlex Crichton }
4871b27508aSPeter Huene
4881b27508aSPeter Huene #[test]
multi_memory_with_imported_memories() -> Result<()>4891b27508aSPeter Huene fn multi_memory_with_imported_memories() -> Result<()> {
4901b27508aSPeter Huene // This test checks that the base address for the defined memory is correct for the instance
4911b27508aSPeter Huene // despite the presence of an imported memory.
4921b27508aSPeter Huene
493a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
494a34427a3SNick Fitzgerald pool.total_memories(2).max_memories_per_module(2);
4951b27508aSPeter Huene let mut config = Config::new();
496c0f03d08SAlex Crichton config.allocation_strategy(pool);
4971b27508aSPeter Huene config.wasm_multi_memory(true);
4981b27508aSPeter Huene
4991b27508aSPeter Huene let engine = Engine::new(&config)?;
5001b27508aSPeter Huene let module = Module::new(
5011b27508aSPeter Huene &engine,
5021b27508aSPeter Huene r#"(module (import "" "m1" (memory 0)) (memory (export "m2") 1))"#,
5031b27508aSPeter Huene )?;
5041b27508aSPeter Huene
5051b27508aSPeter Huene let mut store = Store::new(&engine, ());
5061b27508aSPeter Huene
5071b27508aSPeter Huene let m1 = Memory::new(&mut store, MemoryType::new(0, None))?;
5081b27508aSPeter Huene let instance = Instance::new(&mut store, &module, &[m1.into()])?;
5091b27508aSPeter Huene
5101b27508aSPeter Huene let m2 = instance.get_memory(&mut store, "m2").unwrap();
5111b27508aSPeter Huene
5121b27508aSPeter Huene m2.data_mut(&mut store)[0] = 0x42;
5131b27508aSPeter Huene assert_eq!(m2.data(&store)[0], 0x42);
5141b27508aSPeter Huene
5151b27508aSPeter Huene Ok(())
5161b27508aSPeter Huene }
517ef17a368SPeter Huene
518ef17a368SPeter Huene #[test]
drop_externref_global_during_module_init() -> Result<()>519ef17a368SPeter Huene fn drop_externref_global_during_module_init() -> Result<()> {
520ef17a368SPeter Huene struct Limiter;
521ef17a368SPeter Huene
522ef17a368SPeter Huene impl ResourceLimiter for Limiter {
52352e90532SAlex Crichton fn memory_growing(&mut self, _: usize, _: usize, _: Option<usize>) -> Result<bool> {
52452e90532SAlex Crichton Ok(false)
525ef17a368SPeter Huene }
526ef17a368SPeter Huene
527df69b9a7SLinwei Shang fn table_growing(&mut self, _: usize, _: usize, _: Option<usize>) -> Result<bool> {
52852e90532SAlex Crichton Ok(false)
529ef17a368SPeter Huene }
530ef17a368SPeter Huene }
531ef17a368SPeter Huene
532a34427a3SNick Fitzgerald let pool = crate::small_pool_config();
533ef17a368SPeter Huene let mut config = Config::new();
534ef17a368SPeter Huene config.wasm_reference_types(true);
535c0f03d08SAlex Crichton config.allocation_strategy(pool);
536ef17a368SPeter Huene
537ef17a368SPeter Huene let engine = Engine::new(&config)?;
538ef17a368SPeter Huene
539ef17a368SPeter Huene let module = Module::new(
540ef17a368SPeter Huene &engine,
541ef17a368SPeter Huene r#"
542ef17a368SPeter Huene (module
543ef17a368SPeter Huene (global i32 (i32.const 1))
544ef17a368SPeter Huene (global i32 (i32.const 2))
545ef17a368SPeter Huene (global i32 (i32.const 3))
546ef17a368SPeter Huene (global i32 (i32.const 4))
547ef17a368SPeter Huene (global i32 (i32.const 5))
548ef17a368SPeter Huene )
549ef17a368SPeter Huene "#,
550ef17a368SPeter Huene )?;
551ef17a368SPeter Huene
552ef17a368SPeter Huene let mut store = Store::new(&engine, Limiter);
5537f0228c9SAlex Crichton Instance::new(&mut store, &module, &[])?;
554ef17a368SPeter Huene drop(store);
555ef17a368SPeter Huene
556ef17a368SPeter Huene let module = Module::new(
557ef17a368SPeter Huene &engine,
558ef17a368SPeter Huene r#"
559ef17a368SPeter Huene (module
560ef17a368SPeter Huene (memory 1)
561ef17a368SPeter Huene (global (mut externref) (ref.null extern))
562ef17a368SPeter Huene )
563ef17a368SPeter Huene "#,
564ef17a368SPeter Huene )?;
565ef17a368SPeter Huene
566ef17a368SPeter Huene let mut store = Store::new(&engine, Limiter);
567ef17a368SPeter Huene store.limiter(|s| s);
568ef17a368SPeter Huene assert!(Instance::new(&mut store, &module, &[]).is_err());
569ef17a368SPeter Huene
570ef17a368SPeter Huene Ok(())
571ef17a368SPeter Huene }
57215bb0c69SAlex Crichton
57315bb0c69SAlex Crichton #[test]
574c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
switch_image_and_non_image() -> Result<()>5753535acbfSAlex Crichton fn switch_image_and_non_image() -> Result<()> {
576a34427a3SNick Fitzgerald let pool = crate::small_pool_config();
5773535acbfSAlex Crichton let mut c = Config::new();
578c0f03d08SAlex Crichton c.allocation_strategy(pool);
5793535acbfSAlex Crichton let engine = Engine::new(&c)?;
5803535acbfSAlex Crichton let module1 = Module::new(
5813535acbfSAlex Crichton &engine,
5823535acbfSAlex Crichton r#"
5833535acbfSAlex Crichton (module
5843535acbfSAlex Crichton (memory 1)
5853535acbfSAlex Crichton (func (export "load") (param i32) (result i32)
5863535acbfSAlex Crichton local.get 0
5873535acbfSAlex Crichton i32.load
5883535acbfSAlex Crichton )
5893535acbfSAlex Crichton )
5903535acbfSAlex Crichton "#,
5913535acbfSAlex Crichton )?;
5923535acbfSAlex Crichton let module2 = Module::new(
5933535acbfSAlex Crichton &engine,
5943535acbfSAlex Crichton r#"
5953535acbfSAlex Crichton (module
5963535acbfSAlex Crichton (memory (export "memory") 1)
5973535acbfSAlex Crichton (data (i32.const 0) "1234")
5983535acbfSAlex Crichton )
5993535acbfSAlex Crichton "#,
6003535acbfSAlex Crichton )?;
6013535acbfSAlex Crichton
6023535acbfSAlex Crichton let assert_zero = || -> Result<()> {
6033535acbfSAlex Crichton let mut store = Store::new(&engine, ());
6043535acbfSAlex Crichton let instance = Instance::new(&mut store, &module1, &[])?;
605b0939f66SAlex Crichton let func = instance.get_typed_func::<i32, i32>(&mut store, "load")?;
6063535acbfSAlex Crichton assert_eq!(func.call(&mut store, 0)?, 0);
6073535acbfSAlex Crichton Ok(())
6083535acbfSAlex Crichton };
6093535acbfSAlex Crichton
6103535acbfSAlex Crichton // Initialize with a heap image and make sure the next instance, without an
6113535acbfSAlex Crichton // image, is zeroed
6123535acbfSAlex Crichton Instance::new(&mut Store::new(&engine, ()), &module2, &[])?;
6133535acbfSAlex Crichton assert_zero()?;
6143535acbfSAlex Crichton
6153535acbfSAlex Crichton // ... transition back to heap image and do this again
6163535acbfSAlex Crichton Instance::new(&mut Store::new(&engine, ()), &module2, &[])?;
6173535acbfSAlex Crichton assert_zero()?;
6183535acbfSAlex Crichton
6193535acbfSAlex Crichton // And go back to an image and make sure it's read/write on the host.
6203535acbfSAlex Crichton let mut store = Store::new(&engine, ());
6213535acbfSAlex Crichton let instance = Instance::new(&mut store, &module2, &[])?;
6223535acbfSAlex Crichton let memory = instance.get_memory(&mut store, "memory").unwrap();
6233535acbfSAlex Crichton let mem = memory.data_mut(&mut store);
6243535acbfSAlex Crichton assert!(mem.starts_with(b"1234"));
6253535acbfSAlex Crichton mem[..6].copy_from_slice(b"567890");
6263535acbfSAlex Crichton
6273535acbfSAlex Crichton Ok(())
6283535acbfSAlex Crichton }
6293535acbfSAlex Crichton
6303535acbfSAlex Crichton #[test]
63115bb0c69SAlex Crichton #[cfg(target_pointer_width = "64")]
632c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
instance_too_large() -> Result<()>63315bb0c69SAlex Crichton fn instance_too_large() -> Result<()> {
634a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
635a34427a3SNick Fitzgerald pool.max_core_instance_size(16);
63615bb0c69SAlex Crichton let mut config = Config::new();
637c0f03d08SAlex Crichton config.allocation_strategy(pool);
63815bb0c69SAlex Crichton
63915bb0c69SAlex Crichton let engine = Engine::new(&config)?;
64015bb0c69SAlex Crichton match Module::new(&engine, "(module)") {
64115bb0c69SAlex Crichton Ok(_) => panic!("should have failed to compile"),
64242bb677fSAlex Crichton Err(e) => {
64342bb677fSAlex Crichton e.assert_contains("exceeds the configured maximum of 16 bytes");
64442bb677fSAlex Crichton e.assert_contains("breakdown of allocation requirement");
64542bb677fSAlex Crichton e.assert_contains("instance state management");
64642bb677fSAlex Crichton e.assert_contains("static vmctx data");
64742bb677fSAlex Crichton }
64815bb0c69SAlex Crichton }
64915bb0c69SAlex Crichton
65015bb0c69SAlex Crichton let mut lots_of_globals = format!("(module");
65115bb0c69SAlex Crichton for _ in 0..100 {
65215bb0c69SAlex Crichton lots_of_globals.push_str("(global i32 i32.const 0)\n");
65315bb0c69SAlex Crichton }
65415bb0c69SAlex Crichton lots_of_globals.push_str(")");
65515bb0c69SAlex Crichton
65615bb0c69SAlex Crichton match Module::new(&engine, &lots_of_globals) {
65715bb0c69SAlex Crichton Ok(_) => panic!("should have failed to compile"),
65842bb677fSAlex Crichton Err(e) => {
65942bb677fSAlex Crichton e.assert_contains("exceeds the configured maximum of 16 bytes");
66042bb677fSAlex Crichton e.assert_contains("breakdown of allocation requirement");
66142bb677fSAlex Crichton e.assert_contains("defined globals");
66242bb677fSAlex Crichton e.assert_contains("instance state management");
66342bb677fSAlex Crichton }
66415bb0c69SAlex Crichton }
66515bb0c69SAlex Crichton
66615bb0c69SAlex Crichton Ok(())
66715bb0c69SAlex Crichton }
66850cffad0SAlex Crichton
66950cffad0SAlex Crichton #[test]
670c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
dynamic_memory_pooling_allocator() -> Result<()>67150cffad0SAlex Crichton fn dynamic_memory_pooling_allocator() -> Result<()> {
6722e48babfSNick Fitzgerald for guard_size in [0, 1 << 16] {
673*39e910beSAlex Crichton for signals_based_traps in [false, true] {
67450cffad0SAlex Crichton let max_size = 128 << 20;
675a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
676906ea017SAlex Crichton pool.max_memory_size(max_size as usize);
67750cffad0SAlex Crichton let mut config = Config::new();
6787a28a5b9SAlex Crichton config.memory_reservation(max_size);
67948d5338bSAlex Crichton config.memory_guard_size(guard_size);
680c0f03d08SAlex Crichton config.allocation_strategy(pool);
681*39e910beSAlex Crichton config.signals_based_traps(signals_based_traps);
68250cffad0SAlex Crichton
68350cffad0SAlex Crichton let engine = Engine::new(&config)?;
68450cffad0SAlex Crichton
685*39e910beSAlex Crichton let Ok(module) = Module::new(
68650cffad0SAlex Crichton &engine,
68750cffad0SAlex Crichton r#"
68850cffad0SAlex Crichton (module
68950cffad0SAlex Crichton (memory (export "memory") 1)
69050cffad0SAlex Crichton
69150cffad0SAlex Crichton (func (export "grow") (param i32) (result i32)
69250cffad0SAlex Crichton local.get 0
69350cffad0SAlex Crichton memory.grow)
69450cffad0SAlex Crichton
69550cffad0SAlex Crichton (func (export "size") (result i32)
69650cffad0SAlex Crichton memory.size)
69750cffad0SAlex Crichton
69850cffad0SAlex Crichton (func (export "i32.load") (param i32) (result i32)
69950cffad0SAlex Crichton local.get 0
70050cffad0SAlex Crichton i32.load)
70150cffad0SAlex Crichton
70250cffad0SAlex Crichton (func (export "i32.store") (param i32 i32)
70350cffad0SAlex Crichton local.get 0
70450cffad0SAlex Crichton local.get 1
70550cffad0SAlex Crichton i32.store)
70650cffad0SAlex Crichton
70750cffad0SAlex Crichton (data (i32.const 100) "x")
70850cffad0SAlex Crichton )
70950cffad0SAlex Crichton "#,
710*39e910beSAlex Crichton ) else {
711*39e910beSAlex Crichton // Ignore invalid configurations on 32-bit which can't run with
712*39e910beSAlex Crichton // signals-based-traps.
713*39e910beSAlex Crichton assert!(cfg!(target_pointer_width = "32") && signals_based_traps);
714*39e910beSAlex Crichton continue;
715*39e910beSAlex Crichton };
71650cffad0SAlex Crichton
71750cffad0SAlex Crichton let mut store = Store::new(&engine, ());
71850cffad0SAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
71950cffad0SAlex Crichton
720b0939f66SAlex Crichton let grow = instance.get_typed_func::<u32, i32>(&mut store, "grow")?;
721b0939f66SAlex Crichton let size = instance.get_typed_func::<(), u32>(&mut store, "size")?;
722b0939f66SAlex Crichton let i32_load = instance.get_typed_func::<u32, i32>(&mut store, "i32.load")?;
723b0939f66SAlex Crichton let i32_store = instance.get_typed_func::<(u32, i32), ()>(&mut store, "i32.store")?;
72450cffad0SAlex Crichton let memory = instance.get_memory(&mut store, "memory").unwrap();
72550cffad0SAlex Crichton
72650cffad0SAlex Crichton // basic length 1 tests
72750cffad0SAlex Crichton // assert_eq!(memory.grow(&mut store, 1)?, 0);
72850cffad0SAlex Crichton assert_eq!(memory.size(&store), 1);
72950cffad0SAlex Crichton assert_eq!(size.call(&mut store, ())?, 1);
73050cffad0SAlex Crichton assert_eq!(i32_load.call(&mut store, 0)?, 0);
73150cffad0SAlex Crichton assert_eq!(i32_load.call(&mut store, 100)?, i32::from(b'x'));
73250cffad0SAlex Crichton i32_store.call(&mut store, (0, 0))?;
73350cffad0SAlex Crichton i32_store.call(&mut store, (100, i32::from(b'y')))?;
73450cffad0SAlex Crichton assert_eq!(i32_load.call(&mut store, 100)?, i32::from(b'y'));
73550cffad0SAlex Crichton
73650cffad0SAlex Crichton // basic length 2 tests
73750cffad0SAlex Crichton let page = 64 * 1024;
73850cffad0SAlex Crichton assert_eq!(grow.call(&mut store, 1)?, 1);
73950cffad0SAlex Crichton assert_eq!(memory.size(&store), 2);
74050cffad0SAlex Crichton assert_eq!(size.call(&mut store, ())?, 2);
74150cffad0SAlex Crichton i32_store.call(&mut store, (page, 200))?;
74250cffad0SAlex Crichton assert_eq!(i32_load.call(&mut store, page)?, 200);
74350cffad0SAlex Crichton
74450cffad0SAlex Crichton // test writes are visible
74550cffad0SAlex Crichton i32_store.call(&mut store, (2, 100))?;
74650cffad0SAlex Crichton assert_eq!(i32_load.call(&mut store, 2)?, 100);
74750cffad0SAlex Crichton
74850cffad0SAlex Crichton // test growth can't exceed maximum
74950cffad0SAlex Crichton let too_many = max_size / (64 * 1024);
75050cffad0SAlex Crichton assert_eq!(grow.call(&mut store, too_many as u32)?, -1);
75150cffad0SAlex Crichton assert!(memory.grow(&mut store, too_many).is_err());
75250cffad0SAlex Crichton
75350cffad0SAlex Crichton assert_eq!(memory.data(&store)[page as usize], 200);
75450cffad0SAlex Crichton
75550cffad0SAlex Crichton // Re-instantiate in another store.
75650cffad0SAlex Crichton store = Store::new(&engine, ());
75750cffad0SAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
758b0939f66SAlex Crichton let i32_load = instance.get_typed_func::<u32, i32>(&mut store, "i32.load")?;
75950cffad0SAlex Crichton let memory = instance.get_memory(&mut store, "memory").unwrap();
76050cffad0SAlex Crichton
7612e48babfSNick Fitzgerald // This is out of bounds...
76250cffad0SAlex Crichton assert!(i32_load.call(&mut store, page).is_err());
7632e48babfSNick Fitzgerald assert_eq!(memory.data_size(&store), page as usize);
7642e48babfSNick Fitzgerald
7652e48babfSNick Fitzgerald // ... but implementation-wise it should still be mapped memory from
7662e48babfSNick Fitzgerald // before if we don't have any guard pages.
7672e48babfSNick Fitzgerald //
76850cffad0SAlex Crichton // Note though that prior writes should all appear as zeros and we can't see
76950cffad0SAlex Crichton // data from the prior instance.
77050cffad0SAlex Crichton //
77150cffad0SAlex Crichton // Note that this part is only implemented on Linux which has
77250cffad0SAlex Crichton // `MADV_DONTNEED`.
773*39e910beSAlex Crichton if cfg!(target_os = "linux") && guard_size == 0 && !signals_based_traps {
77450cffad0SAlex Crichton unsafe {
77550cffad0SAlex Crichton let ptr = memory.data_ptr(&store);
77650cffad0SAlex Crichton assert_eq!(*ptr.offset(page as isize), 0);
77750cffad0SAlex Crichton }
77850cffad0SAlex Crichton }
7792e48babfSNick Fitzgerald }
780*39e910beSAlex Crichton }
78150cffad0SAlex Crichton
78250cffad0SAlex Crichton Ok(())
78350cffad0SAlex Crichton }
784000bd98aSAlex Crichton
785000bd98aSAlex Crichton #[test]
786c0bb341dSAlex Crichton #[cfg_attr(miri, ignore)]
zero_memory_pages_disallows_oob() -> Result<()>787000bd98aSAlex Crichton fn zero_memory_pages_disallows_oob() -> Result<()> {
788a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
789906ea017SAlex Crichton pool.max_memory_size(0);
790000bd98aSAlex Crichton let mut config = Config::new();
791c0f03d08SAlex Crichton config.allocation_strategy(pool);
792000bd98aSAlex Crichton
793000bd98aSAlex Crichton let engine = Engine::new(&config)?;
794000bd98aSAlex Crichton let module = Module::new(
795000bd98aSAlex Crichton &engine,
796000bd98aSAlex Crichton r#"
797000bd98aSAlex Crichton (module
798000bd98aSAlex Crichton (memory 0)
799000bd98aSAlex Crichton
800000bd98aSAlex Crichton (func (export "load") (param i32) (result i32)
801000bd98aSAlex Crichton local.get 0
802000bd98aSAlex Crichton i32.load)
803000bd98aSAlex Crichton
804000bd98aSAlex Crichton (func (export "store") (param i32 )
805000bd98aSAlex Crichton local.get 0
806000bd98aSAlex Crichton local.get 0
807000bd98aSAlex Crichton i32.store)
808000bd98aSAlex Crichton )
809000bd98aSAlex Crichton "#,
810000bd98aSAlex Crichton )?;
811000bd98aSAlex Crichton let mut store = Store::new(&engine, ());
812000bd98aSAlex Crichton let instance = Instance::new(&mut store, &module, &[])?;
813b0939f66SAlex Crichton let load32 = instance.get_typed_func::<i32, i32>(&mut store, "load")?;
814b0939f66SAlex Crichton let store32 = instance.get_typed_func::<i32, ()>(&mut store, "store")?;
815000bd98aSAlex Crichton for i in 0..31 {
816000bd98aSAlex Crichton assert!(load32.call(&mut store, 1 << i).is_err());
817000bd98aSAlex Crichton assert!(store32.call(&mut store, 1 << i).is_err());
818000bd98aSAlex Crichton }
819000bd98aSAlex Crichton Ok(())
820000bd98aSAlex Crichton }
821a34427a3SNick Fitzgerald
822a34427a3SNick Fitzgerald #[test]
823a34427a3SNick Fitzgerald #[cfg(feature = "component-model")]
total_component_instances_limit() -> Result<()>824a34427a3SNick Fitzgerald fn total_component_instances_limit() -> Result<()> {
825a34427a3SNick Fitzgerald const TOTAL_COMPONENT_INSTANCES: u32 = 5;
826a34427a3SNick Fitzgerald
827a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
828a34427a3SNick Fitzgerald pool.total_component_instances(TOTAL_COMPONENT_INSTANCES);
829a34427a3SNick Fitzgerald let mut config = Config::new();
830a34427a3SNick Fitzgerald config.wasm_component_model(true);
831c0f03d08SAlex Crichton config.allocation_strategy(pool);
832a34427a3SNick Fitzgerald
833a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
834a34427a3SNick Fitzgerald let linker = wasmtime::component::Linker::new(&engine);
835a34427a3SNick Fitzgerald let component = wasmtime::component::Component::new(&engine, "(component)")?;
836a34427a3SNick Fitzgerald
837a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
838a34427a3SNick Fitzgerald for _ in 0..TOTAL_COMPONENT_INSTANCES {
839a34427a3SNick Fitzgerald linker.instantiate(&mut store, &component)?;
840a34427a3SNick Fitzgerald }
841a34427a3SNick Fitzgerald
842a34427a3SNick Fitzgerald match linker.instantiate(&mut store, &component) {
843a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit component instance limit"),
844e1f8b9b7SNick Fitzgerald Err(e) => assert!(e.is::<PoolConcurrencyLimitError>()),
845a34427a3SNick Fitzgerald }
846a34427a3SNick Fitzgerald
847a34427a3SNick Fitzgerald drop(store);
848a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
849a34427a3SNick Fitzgerald for _ in 0..TOTAL_COMPONENT_INSTANCES {
850a34427a3SNick Fitzgerald linker.instantiate(&mut store, &component)?;
851a34427a3SNick Fitzgerald }
852a34427a3SNick Fitzgerald
853a34427a3SNick Fitzgerald Ok(())
854a34427a3SNick Fitzgerald }
855a34427a3SNick Fitzgerald
856a34427a3SNick Fitzgerald #[test]
857a34427a3SNick Fitzgerald #[cfg(feature = "component-model")]
85848f4621fSAlex Crichton #[cfg(target_pointer_width = "64")] // error message tailored for 64-bit
component_instance_size_limit() -> Result<()>859a34427a3SNick Fitzgerald fn component_instance_size_limit() -> Result<()> {
860a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
861a34427a3SNick Fitzgerald pool.max_component_instance_size(1);
862a34427a3SNick Fitzgerald let mut config = Config::new();
863a34427a3SNick Fitzgerald config.wasm_component_model(true);
864c0f03d08SAlex Crichton config.allocation_strategy(pool);
865a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
866a34427a3SNick Fitzgerald
867a34427a3SNick Fitzgerald match wasmtime::component::Component::new(&engine, "(component)") {
868a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit limit"),
869cf138985SPaul Osborne Err(e) => {
870cf138985SPaul Osborne e.assert_contains("instance allocation for this component requires 64 bytes");
871cf138985SPaul Osborne e.assert_contains("which exceeds the configured maximum of 1 bytes");
872cf138985SPaul Osborne e.assert_contains("`VMComponentContext` used 64 bytes");
873cf138985SPaul Osborne }
874a34427a3SNick Fitzgerald }
875a34427a3SNick Fitzgerald
876a34427a3SNick Fitzgerald Ok(())
877a34427a3SNick Fitzgerald }
878a34427a3SNick Fitzgerald
879a34427a3SNick Fitzgerald #[test]
880a34427a3SNick Fitzgerald #[cfg_attr(miri, ignore)]
total_tables_limit() -> Result<()>881a34427a3SNick Fitzgerald fn total_tables_limit() -> Result<()> {
882a34427a3SNick Fitzgerald const TOTAL_TABLES: u32 = 5;
883a34427a3SNick Fitzgerald
884a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
885a34427a3SNick Fitzgerald pool.total_tables(TOTAL_TABLES)
886a34427a3SNick Fitzgerald .total_core_instances(TOTAL_TABLES + 1);
887a34427a3SNick Fitzgerald let mut config = Config::new();
888c0f03d08SAlex Crichton config.allocation_strategy(pool);
889a34427a3SNick Fitzgerald
890a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
891a34427a3SNick Fitzgerald let linker = Linker::new(&engine);
892a34427a3SNick Fitzgerald let module = Module::new(&engine, "(module (table 0 1 funcref))")?;
893a34427a3SNick Fitzgerald
894a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
895a34427a3SNick Fitzgerald for _ in 0..TOTAL_TABLES {
896a34427a3SNick Fitzgerald linker.instantiate(&mut store, &module)?;
897a34427a3SNick Fitzgerald }
898a34427a3SNick Fitzgerald
899a34427a3SNick Fitzgerald match linker.instantiate(&mut store, &module) {
900a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit table limit"),
901e1f8b9b7SNick Fitzgerald Err(e) => assert!(e.is::<PoolConcurrencyLimitError>()),
902a34427a3SNick Fitzgerald }
903a34427a3SNick Fitzgerald
904a34427a3SNick Fitzgerald drop(store);
905a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
906a34427a3SNick Fitzgerald for _ in 0..TOTAL_TABLES {
907a34427a3SNick Fitzgerald linker.instantiate(&mut store, &module)?;
908a34427a3SNick Fitzgerald }
909a34427a3SNick Fitzgerald
910a34427a3SNick Fitzgerald Ok(())
911a34427a3SNick Fitzgerald }
912a34427a3SNick Fitzgerald
913a34427a3SNick Fitzgerald #[tokio::test]
914a34427a3SNick Fitzgerald #[cfg(not(miri))]
total_stacks_limit() -> Result<()>915a34427a3SNick Fitzgerald async fn total_stacks_limit() -> Result<()> {
916a34427a3SNick Fitzgerald use super::async_functions::PollOnce;
917a34427a3SNick Fitzgerald
918a34427a3SNick Fitzgerald const TOTAL_STACKS: u32 = 2;
919a34427a3SNick Fitzgerald
920a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
921a34427a3SNick Fitzgerald pool.total_stacks(TOTAL_STACKS)
922a34427a3SNick Fitzgerald .total_core_instances(TOTAL_STACKS + 1);
923a34427a3SNick Fitzgerald let mut config = Config::new();
924c0f03d08SAlex Crichton config.allocation_strategy(pool);
925a34427a3SNick Fitzgerald
926a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
927a34427a3SNick Fitzgerald
928a34427a3SNick Fitzgerald let mut linker = Linker::new(&engine);
929a34427a3SNick Fitzgerald linker.func_new_async(
930a34427a3SNick Fitzgerald "async",
931a34427a3SNick Fitzgerald "yield",
9328652011fSNick Fitzgerald FuncType::new(&engine, [], []),
933a34427a3SNick Fitzgerald |_caller, _params, _results| {
934a34427a3SNick Fitzgerald Box::new(async {
935a34427a3SNick Fitzgerald tokio::task::yield_now().await;
936a34427a3SNick Fitzgerald Ok(())
937a34427a3SNick Fitzgerald })
938a34427a3SNick Fitzgerald },
939a34427a3SNick Fitzgerald )?;
940a34427a3SNick Fitzgerald
941a34427a3SNick Fitzgerald let module = Module::new(
942a34427a3SNick Fitzgerald &engine,
943a34427a3SNick Fitzgerald r#"
944a34427a3SNick Fitzgerald (module
945a34427a3SNick Fitzgerald (import "async" "yield" (func $yield))
946a34427a3SNick Fitzgerald (func (export "run")
947a34427a3SNick Fitzgerald call $yield
948a34427a3SNick Fitzgerald )
949e1f50aadSAlex Crichton
950e1f50aadSAlex Crichton (func $empty)
951e1f50aadSAlex Crichton (start $empty)
952a34427a3SNick Fitzgerald )
953a34427a3SNick Fitzgerald "#,
954a34427a3SNick Fitzgerald )?;
955a34427a3SNick Fitzgerald
956a34427a3SNick Fitzgerald // Allocate stacks up to the limit. (Poll the futures once to make sure we
957a34427a3SNick Fitzgerald // actually enter Wasm and force a stack allocation.)
958a34427a3SNick Fitzgerald
959a34427a3SNick Fitzgerald let mut store1 = Store::new(&engine, ());
960a34427a3SNick Fitzgerald let instance1 = linker.instantiate_async(&mut store1, &module).await?;
961a34427a3SNick Fitzgerald let run1 = instance1.get_func(&mut store1, "run").unwrap();
962a34427a3SNick Fitzgerald let future1 = PollOnce::new(Box::pin(run1.call_async(store1, &[], &mut [])))
963a34427a3SNick Fitzgerald .await
964a34427a3SNick Fitzgerald .unwrap_err();
965a34427a3SNick Fitzgerald
966a34427a3SNick Fitzgerald let mut store2 = Store::new(&engine, ());
967a34427a3SNick Fitzgerald let instance2 = linker.instantiate_async(&mut store2, &module).await?;
968a34427a3SNick Fitzgerald let run2 = instance2.get_func(&mut store2, "run").unwrap();
969a34427a3SNick Fitzgerald let future2 = PollOnce::new(Box::pin(run2.call_async(store2, &[], &mut [])))
970a34427a3SNick Fitzgerald .await
971a34427a3SNick Fitzgerald .unwrap_err();
972a34427a3SNick Fitzgerald
973a34427a3SNick Fitzgerald // Allocating more should fail.
974a34427a3SNick Fitzgerald let mut store3 = Store::new(&engine, ());
975a34427a3SNick Fitzgerald match linker.instantiate_async(&mut store3, &module).await {
976a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit stack limit"),
977e1f8b9b7SNick Fitzgerald Err(e) => assert!(e.is::<PoolConcurrencyLimitError>()),
978a34427a3SNick Fitzgerald }
979a34427a3SNick Fitzgerald
980a34427a3SNick Fitzgerald // Finish the futures and return their Wasm stacks to the pool.
981a34427a3SNick Fitzgerald future1.await?;
982a34427a3SNick Fitzgerald future2.await?;
983a34427a3SNick Fitzgerald
984a34427a3SNick Fitzgerald // Should be able to allocate new stacks again.
985a34427a3SNick Fitzgerald let mut store1 = Store::new(&engine, ());
986a34427a3SNick Fitzgerald let instance1 = linker.instantiate_async(&mut store1, &module).await?;
987a34427a3SNick Fitzgerald let run1 = instance1.get_func(&mut store1, "run").unwrap();
988be40551fSAlex Crichton let future1 = run1.call_async(&mut store1, &[], &mut []);
989a34427a3SNick Fitzgerald
990a34427a3SNick Fitzgerald let mut store2 = Store::new(&engine, ());
991a34427a3SNick Fitzgerald let instance2 = linker.instantiate_async(&mut store2, &module).await?;
992a34427a3SNick Fitzgerald let run2 = instance2.get_func(&mut store2, "run").unwrap();
993be40551fSAlex Crichton let future2 = run2.call_async(&mut store2, &[], &mut []);
994a34427a3SNick Fitzgerald
995a34427a3SNick Fitzgerald future1.await?;
996a34427a3SNick Fitzgerald future2.await?;
997a34427a3SNick Fitzgerald
998be40551fSAlex Crichton // Dispose one store via `Drop`, the other via `into_data`, and ensure that
999be40551fSAlex Crichton // any lingering stacks make their way back to the pool.
1000be40551fSAlex Crichton drop(store1);
1001be40551fSAlex Crichton store2.into_data();
1002be40551fSAlex Crichton
1003a34427a3SNick Fitzgerald Ok(())
1004a34427a3SNick Fitzgerald }
1005a34427a3SNick Fitzgerald
1006a34427a3SNick Fitzgerald #[test]
1007a34427a3SNick Fitzgerald #[cfg(feature = "component-model")]
component_core_instances_limit() -> Result<()>1008a34427a3SNick Fitzgerald fn component_core_instances_limit() -> Result<()> {
1009a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
1010a34427a3SNick Fitzgerald pool.max_core_instances_per_component(1);
1011a34427a3SNick Fitzgerald let mut config = Config::new();
1012a34427a3SNick Fitzgerald config.wasm_component_model(true);
1013c0f03d08SAlex Crichton config.allocation_strategy(pool);
1014a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
1015a34427a3SNick Fitzgerald
1016a34427a3SNick Fitzgerald // One core instance works.
1017a34427a3SNick Fitzgerald wasmtime::component::Component::new(
1018a34427a3SNick Fitzgerald &engine,
1019a34427a3SNick Fitzgerald r#"
1020a34427a3SNick Fitzgerald (component
1021a34427a3SNick Fitzgerald (core module $m)
1022a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1023a34427a3SNick Fitzgerald )
1024a34427a3SNick Fitzgerald "#,
1025a34427a3SNick Fitzgerald )?;
1026a34427a3SNick Fitzgerald
1027a34427a3SNick Fitzgerald // Two core instances doesn't.
1028a34427a3SNick Fitzgerald match wasmtime::component::Component::new(
1029a34427a3SNick Fitzgerald &engine,
1030a34427a3SNick Fitzgerald r#"
1031a34427a3SNick Fitzgerald (component
1032a34427a3SNick Fitzgerald (core module $m)
1033a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1034a34427a3SNick Fitzgerald (core instance $b (instantiate $m))
1035a34427a3SNick Fitzgerald )
1036a34427a3SNick Fitzgerald "#,
1037a34427a3SNick Fitzgerald ) {
1038a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit limit"),
103942bb677fSAlex Crichton Err(e) => e.assert_contains(
1040a34427a3SNick Fitzgerald "The component transitively contains 2 core module instances, which exceeds the \
104142bb677fSAlex Crichton configured maximum of 1",
1042a34427a3SNick Fitzgerald ),
1043a34427a3SNick Fitzgerald }
1044a34427a3SNick Fitzgerald
1045a34427a3SNick Fitzgerald Ok(())
1046a34427a3SNick Fitzgerald }
1047a34427a3SNick Fitzgerald
1048a34427a3SNick Fitzgerald #[test]
1049a34427a3SNick Fitzgerald #[cfg(feature = "component-model")]
component_memories_limit() -> Result<()>1050a34427a3SNick Fitzgerald fn component_memories_limit() -> Result<()> {
1051a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
1052a34427a3SNick Fitzgerald pool.max_memories_per_component(1).total_memories(2);
1053a34427a3SNick Fitzgerald let mut config = Config::new();
1054a34427a3SNick Fitzgerald config.wasm_component_model(true);
1055c0f03d08SAlex Crichton config.allocation_strategy(pool);
1056a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
1057a34427a3SNick Fitzgerald
1058a34427a3SNick Fitzgerald // One memory works.
1059a34427a3SNick Fitzgerald wasmtime::component::Component::new(
1060a34427a3SNick Fitzgerald &engine,
1061a34427a3SNick Fitzgerald r#"
1062a34427a3SNick Fitzgerald (component
1063a34427a3SNick Fitzgerald (core module $m (memory 1 1))
1064a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1065a34427a3SNick Fitzgerald )
1066a34427a3SNick Fitzgerald "#,
1067a34427a3SNick Fitzgerald )?;
1068a34427a3SNick Fitzgerald
1069a34427a3SNick Fitzgerald // Two memories doesn't.
1070a34427a3SNick Fitzgerald match wasmtime::component::Component::new(
1071a34427a3SNick Fitzgerald &engine,
1072a34427a3SNick Fitzgerald r#"
1073a34427a3SNick Fitzgerald (component
1074a34427a3SNick Fitzgerald (core module $m (memory 1 1))
1075a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1076a34427a3SNick Fitzgerald (core instance $b (instantiate $m))
1077a34427a3SNick Fitzgerald )
1078a34427a3SNick Fitzgerald "#,
1079a34427a3SNick Fitzgerald ) {
1080a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit limit"),
108142bb677fSAlex Crichton Err(e) => e.assert_contains(
1082a34427a3SNick Fitzgerald "The component transitively contains 2 Wasm linear memories, which exceeds the \
108342bb677fSAlex Crichton configured maximum of 1",
1084a34427a3SNick Fitzgerald ),
1085a34427a3SNick Fitzgerald }
1086a34427a3SNick Fitzgerald
1087a34427a3SNick Fitzgerald Ok(())
1088a34427a3SNick Fitzgerald }
1089a34427a3SNick Fitzgerald
1090a34427a3SNick Fitzgerald #[test]
1091a34427a3SNick Fitzgerald #[cfg(feature = "component-model")]
component_tables_limit() -> Result<()>1092a34427a3SNick Fitzgerald fn component_tables_limit() -> Result<()> {
1093a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
1094a34427a3SNick Fitzgerald pool.max_tables_per_component(1).total_tables(2);
1095a34427a3SNick Fitzgerald let mut config = Config::new();
1096a34427a3SNick Fitzgerald config.wasm_component_model(true);
1097c0f03d08SAlex Crichton config.allocation_strategy(pool);
1098a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
1099a34427a3SNick Fitzgerald
1100a34427a3SNick Fitzgerald // One table works.
1101a34427a3SNick Fitzgerald wasmtime::component::Component::new(
1102a34427a3SNick Fitzgerald &engine,
1103a34427a3SNick Fitzgerald r#"
1104a34427a3SNick Fitzgerald (component
1105a34427a3SNick Fitzgerald (core module $m (table 1 1 funcref))
1106a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1107a34427a3SNick Fitzgerald )
1108a34427a3SNick Fitzgerald "#,
1109a34427a3SNick Fitzgerald )?;
1110a34427a3SNick Fitzgerald
1111a34427a3SNick Fitzgerald // Two tables doesn't.
1112a34427a3SNick Fitzgerald match wasmtime::component::Component::new(
1113a34427a3SNick Fitzgerald &engine,
1114a34427a3SNick Fitzgerald r#"
1115a34427a3SNick Fitzgerald (component
1116a34427a3SNick Fitzgerald (core module $m (table 1 1 funcref))
1117a34427a3SNick Fitzgerald (core instance $a (instantiate $m))
1118a34427a3SNick Fitzgerald (core instance $b (instantiate $m))
1119a34427a3SNick Fitzgerald )
1120a34427a3SNick Fitzgerald "#,
1121a34427a3SNick Fitzgerald ) {
1122a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit limit"),
112342bb677fSAlex Crichton Err(e) => e.assert_contains(
1124a34427a3SNick Fitzgerald "The component transitively contains 2 tables, which exceeds the \
112542bb677fSAlex Crichton configured maximum of 1",
1126a34427a3SNick Fitzgerald ),
1127a34427a3SNick Fitzgerald }
1128a34427a3SNick Fitzgerald
1129a34427a3SNick Fitzgerald Ok(())
1130a34427a3SNick Fitzgerald }
1131a34427a3SNick Fitzgerald
1132a34427a3SNick Fitzgerald #[test]
1133cf138985SPaul Osborne #[cfg(feature = "component-model")]
1134cf138985SPaul Osborne #[cfg_attr(miri, ignore)]
component_core_instances_aggregate_size() -> Result<()>1135cf138985SPaul Osborne fn component_core_instances_aggregate_size() -> Result<()> {
1136cf138985SPaul Osborne let mut pool = crate::small_pool_config();
1137cf138985SPaul Osborne pool.max_core_instances_per_component(100)
1138cf138985SPaul Osborne // x86_64 requires 23824 bytes; we exceed this by a fair bit as there will
1139cf138985SPaul Osborne // be differences by arch.
1140cf138985SPaul Osborne .max_component_instance_size(1024);
1141cf138985SPaul Osborne
1142cf138985SPaul Osborne let mut config = Config::new();
1143cf138985SPaul Osborne config.wasm_component_model(true);
1144cf138985SPaul Osborne config.allocation_strategy(pool);
1145cf138985SPaul Osborne let engine = Engine::new(&config)?;
1146cf138985SPaul Osborne
1147cf138985SPaul Osborne let core_instances = (1..100)
1148cf138985SPaul Osborne .map(|i| format!("(core instance $i{i} (instantiate $m))"))
1149cf138985SPaul Osborne .collect::<Vec<String>>()
1150cf138985SPaul Osborne .join("\n");
1151cf138985SPaul Osborne
1152cf138985SPaul Osborne match wasmtime::component::Component::new(
1153cf138985SPaul Osborne &engine,
1154cf138985SPaul Osborne format!(
1155cf138985SPaul Osborne "
1156cf138985SPaul Osborne (component
1157cf138985SPaul Osborne (core module $m
1158cf138985SPaul Osborne (func (export \"f\") (result i32)
1159cf138985SPaul Osborne i32.const 42
1160cf138985SPaul Osborne )
1161cf138985SPaul Osborne )
1162cf138985SPaul Osborne {core_instances}
1163cf138985SPaul Osborne )
1164cf138985SPaul Osborne "
1165cf138985SPaul Osborne ),
1166cf138985SPaul Osborne ) {
1167cf138985SPaul Osborne Ok(_) => panic!("should have hit aggregate size limit"),
1168cf138985SPaul Osborne Err(e) => {
1169cf138985SPaul Osborne e.assert_contains("instance allocation for this component requires");
1170cf138985SPaul Osborne e.assert_contains("exceeds the configured maximum");
1171cf138985SPaul Osborne }
1172cf138985SPaul Osborne }
1173cf138985SPaul Osborne
1174cf138985SPaul Osborne Ok(())
1175cf138985SPaul Osborne }
1176cf138985SPaul Osborne
1177cf138985SPaul Osborne #[test]
1178a34427a3SNick Fitzgerald #[cfg_attr(miri, ignore)]
total_memories_limit() -> Result<()>1179a34427a3SNick Fitzgerald fn total_memories_limit() -> Result<()> {
1180a34427a3SNick Fitzgerald const TOTAL_MEMORIES: u32 = 5;
1181a34427a3SNick Fitzgerald
1182a34427a3SNick Fitzgerald let mut pool = crate::small_pool_config();
1183a34427a3SNick Fitzgerald pool.total_memories(TOTAL_MEMORIES)
11849db47375SAndrew Brown .total_core_instances(TOTAL_MEMORIES + 1)
1185698028ceSAlex Crichton .memory_protection_keys(Enabled::No);
1186a34427a3SNick Fitzgerald let mut config = Config::new();
1187c0f03d08SAlex Crichton config.allocation_strategy(pool);
1188a34427a3SNick Fitzgerald
1189a34427a3SNick Fitzgerald let engine = Engine::new(&config)?;
1190a34427a3SNick Fitzgerald let linker = Linker::new(&engine);
1191a34427a3SNick Fitzgerald let module = Module::new(&engine, "(module (memory 1 1))")?;
1192a34427a3SNick Fitzgerald
1193a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
1194a34427a3SNick Fitzgerald for _ in 0..TOTAL_MEMORIES {
1195a34427a3SNick Fitzgerald linker.instantiate(&mut store, &module)?;
1196a34427a3SNick Fitzgerald }
1197a34427a3SNick Fitzgerald
1198a34427a3SNick Fitzgerald match linker.instantiate(&mut store, &module) {
1199a34427a3SNick Fitzgerald Ok(_) => panic!("should have hit memory limit"),
1200e1f8b9b7SNick Fitzgerald Err(e) => assert!(e.is::<PoolConcurrencyLimitError>()),
1201a34427a3SNick Fitzgerald }
1202a34427a3SNick Fitzgerald
1203a34427a3SNick Fitzgerald drop(store);
1204a34427a3SNick Fitzgerald let mut store = Store::new(&engine, ());
1205a34427a3SNick Fitzgerald for _ in 0..TOTAL_MEMORIES {
1206a34427a3SNick Fitzgerald linker.instantiate(&mut store, &module)?;
1207a34427a3SNick Fitzgerald }
1208a34427a3SNick Fitzgerald
1209a34427a3SNick Fitzgerald Ok(())
1210a34427a3SNick Fitzgerald }
1211e1f8b9b7SNick Fitzgerald
1212e1f8b9b7SNick Fitzgerald #[test]
1213e1f8b9b7SNick Fitzgerald #[cfg_attr(miri, ignore)]
decommit_batching() -> Result<()>1214e1f8b9b7SNick Fitzgerald fn decommit_batching() -> Result<()> {
1215e1f8b9b7SNick Fitzgerald for (capacity, batch_size) in [
1216e1f8b9b7SNick Fitzgerald // A reasonable batch size.
1217e1f8b9b7SNick Fitzgerald (10, 5),
1218e1f8b9b7SNick Fitzgerald // Batch sizes of zero and one should effectively disable batching.
1219e1f8b9b7SNick Fitzgerald (10, 1),
1220e1f8b9b7SNick Fitzgerald (10, 0),
1221e1f8b9b7SNick Fitzgerald // A bigger batch size than capacity, which forces the allocation path
1222e1f8b9b7SNick Fitzgerald // to flush the decommit queue.
1223e1f8b9b7SNick Fitzgerald (10, 99),
1224e1f8b9b7SNick Fitzgerald ] {
1225e1f8b9b7SNick Fitzgerald let mut pool = crate::small_pool_config();
1226e1f8b9b7SNick Fitzgerald pool.total_memories(capacity)
1227e1f8b9b7SNick Fitzgerald .total_core_instances(capacity)
1228e1f8b9b7SNick Fitzgerald .decommit_batch_size(batch_size)
1229698028ceSAlex Crichton .memory_protection_keys(Enabled::No);
1230e1f8b9b7SNick Fitzgerald let mut config = Config::new();
1231c0f03d08SAlex Crichton config.allocation_strategy(pool);
1232e1f8b9b7SNick Fitzgerald
1233e1f8b9b7SNick Fitzgerald let engine = Engine::new(&config)?;
1234e1f8b9b7SNick Fitzgerald let linker = Linker::new(&engine);
1235e1f8b9b7SNick Fitzgerald let module = Module::new(&engine, "(module (memory 1 1))")?;
1236e1f8b9b7SNick Fitzgerald
1237e1f8b9b7SNick Fitzgerald // Just make sure that we can instantiate all slots a few times and the
1238e1f8b9b7SNick Fitzgerald // pooling allocator must be flushing the decommit queue as necessary.
1239e1f8b9b7SNick Fitzgerald for _ in 0..3 {
1240e1f8b9b7SNick Fitzgerald let mut store = Store::new(&engine, ());
1241e1f8b9b7SNick Fitzgerald for _ in 0..capacity {
1242e1f8b9b7SNick Fitzgerald linker.instantiate(&mut store, &module)?;
1243e1f8b9b7SNick Fitzgerald }
1244e1f8b9b7SNick Fitzgerald }
1245e1f8b9b7SNick Fitzgerald }
1246e1f8b9b7SNick Fitzgerald
1247e1f8b9b7SNick Fitzgerald Ok(())
1248e1f8b9b7SNick Fitzgerald }
1249d88aeda8SAlex Crichton
1250d88aeda8SAlex Crichton #[test]
tricky_empty_table_with_empty_virtual_memory_alloc() -> Result<()>1251d88aeda8SAlex Crichton fn tricky_empty_table_with_empty_virtual_memory_alloc() -> Result<()> {
1252d88aeda8SAlex Crichton // Configure the pooling allocator to have no access to virtual memory, e.g.
1253d88aeda8SAlex Crichton // no table elements but a single table. This should technically support a
1254d88aeda8SAlex Crichton // single empty table being allocated into it but virtual memory isn't
1255d88aeda8SAlex Crichton // actually allocated here.
1256d88aeda8SAlex Crichton let mut cfg = PoolingAllocationConfig::default();
1257d88aeda8SAlex Crichton cfg.table_elements(0);
1258d88aeda8SAlex Crichton cfg.total_memories(0);
1259d88aeda8SAlex Crichton cfg.total_tables(1);
1260d88aeda8SAlex Crichton cfg.total_stacks(0);
1261d88aeda8SAlex Crichton cfg.total_core_instances(1);
1262d88aeda8SAlex Crichton cfg.max_memory_size(0);
1263d88aeda8SAlex Crichton
1264d88aeda8SAlex Crichton let mut c = Config::new();
1265d88aeda8SAlex Crichton c.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
1266d88aeda8SAlex Crichton
1267d88aeda8SAlex Crichton // Disable lazy init to actually try to get this to do something interesting
1268d88aeda8SAlex Crichton // at runtime.
1269d88aeda8SAlex Crichton c.table_lazy_init(false);
1270d88aeda8SAlex Crichton
1271d88aeda8SAlex Crichton let engine = Engine::new(&c)?;
1272d88aeda8SAlex Crichton
1273d88aeda8SAlex Crichton // This module has a single empty table, with a single empty element
1274d88aeda8SAlex Crichton // segment. Nothing actually goes wrong here, it should instantiate
1275d88aeda8SAlex Crichton // successfully. Along the way though the empty mmap above will get viewed
1276d88aeda8SAlex Crichton // as an array-of-pointers, so everything internally should all line up to
1277d88aeda8SAlex Crichton // work ok.
1278d88aeda8SAlex Crichton let module = Module::new(
1279d88aeda8SAlex Crichton &engine,
1280d88aeda8SAlex Crichton r#"
1281d88aeda8SAlex Crichton (module
1282d88aeda8SAlex Crichton (table 0 funcref)
1283d88aeda8SAlex Crichton (elem (i32.const 0) func)
1284d88aeda8SAlex Crichton )
1285d88aeda8SAlex Crichton "#,
1286d88aeda8SAlex Crichton )?;
1287d88aeda8SAlex Crichton let mut store = Store::new(&engine, ());
1288d88aeda8SAlex Crichton Instance::new(&mut store, &module, &[])?;
1289d88aeda8SAlex Crichton Ok(())
1290d88aeda8SAlex Crichton }
129144da0566SAlex Crichton
129244da0566SAlex Crichton #[test]
129344da0566SAlex Crichton #[cfg_attr(miri, ignore)]
shared_memory_unsupported() -> Result<()>12940cabb39eSAlex Crichton fn shared_memory_unsupported() -> Result<()> {
129548f4621fSAlex Crichton // Skip this test on platforms that don't support threads.
129648f4621fSAlex Crichton if crate::threads::engine().is_none() {
129748f4621fSAlex Crichton return Ok(());
129848f4621fSAlex Crichton }
12990cabb39eSAlex Crichton let mut config = Config::new();
13000cabb39eSAlex Crichton let mut cfg = PoolingAllocationConfig::default();
13010cabb39eSAlex Crichton // shrink the size of this allocator
13020cabb39eSAlex Crichton cfg.total_memories(1);
13030cabb39eSAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
13040cabb39eSAlex Crichton let engine = Engine::new(&config)?;
13050cabb39eSAlex Crichton
13060cabb39eSAlex Crichton let err = Module::new(
13070cabb39eSAlex Crichton &engine,
13080cabb39eSAlex Crichton r#"
13090cabb39eSAlex Crichton (module
13100cabb39eSAlex Crichton (memory 5 5 shared)
13110cabb39eSAlex Crichton )
13120cabb39eSAlex Crichton "#,
13130cabb39eSAlex Crichton )
13140cabb39eSAlex Crichton .unwrap_err();
131542bb677fSAlex Crichton err.assert_contains(
1316c22b3cb9SNick Fitzgerald "memory is shared which is not supported \
131742bb677fSAlex Crichton in the pooling allocator",
13180cabb39eSAlex Crichton );
1319c22b3cb9SNick Fitzgerald err.assert_contains("memory index 0");
13200cabb39eSAlex Crichton Ok(())
13210cabb39eSAlex Crichton }
13220cabb39eSAlex Crichton
13230cabb39eSAlex Crichton #[test]
13240cabb39eSAlex Crichton #[cfg_attr(miri, ignore)]
custom_page_sizes_reusing_same_slot() -> Result<()>132544da0566SAlex Crichton fn custom_page_sizes_reusing_same_slot() -> Result<()> {
132644da0566SAlex Crichton let mut config = Config::new();
132744da0566SAlex Crichton config.wasm_custom_page_sizes(true);
132848f4621fSAlex Crichton let mut cfg = crate::small_pool_config();
132944da0566SAlex Crichton // force the memories below to collide in the same memory slot
133044da0566SAlex Crichton cfg.total_memories(1);
133144da0566SAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
133244da0566SAlex Crichton let engine = Engine::new(&config)?;
133344da0566SAlex Crichton
133444da0566SAlex Crichton // Instantiate one module, leaving the slot 5 bytes big (but one page
133544da0566SAlex Crichton // accessible)
133644da0566SAlex Crichton {
133744da0566SAlex Crichton let m1 = Module::new(
133844da0566SAlex Crichton &engine,
133944da0566SAlex Crichton r#"
134044da0566SAlex Crichton (module
134144da0566SAlex Crichton (memory 5 (pagesize 1))
134244da0566SAlex Crichton
134344da0566SAlex Crichton (data (i32.const 0) "a")
134444da0566SAlex Crichton )
134544da0566SAlex Crichton "#,
134644da0566SAlex Crichton )?;
134744da0566SAlex Crichton let mut store = Store::new(&engine, ());
134844da0566SAlex Crichton Instance::new(&mut store, &m1, &[])?;
134944da0566SAlex Crichton }
135044da0566SAlex Crichton
135144da0566SAlex Crichton // Instantiate a second module, which should work
135244da0566SAlex Crichton {
135344da0566SAlex Crichton let m2 = Module::new(
135444da0566SAlex Crichton &engine,
135544da0566SAlex Crichton r#"
135644da0566SAlex Crichton (module
135744da0566SAlex Crichton (memory 6 (pagesize 1))
135844da0566SAlex Crichton
135944da0566SAlex Crichton (data (i32.const 0) "a")
136044da0566SAlex Crichton )
136144da0566SAlex Crichton "#,
136244da0566SAlex Crichton )?;
136344da0566SAlex Crichton let mut store = Store::new(&engine, ());
136444da0566SAlex Crichton Instance::new(&mut store, &m2, &[])?;
136544da0566SAlex Crichton }
136644da0566SAlex Crichton Ok(())
136744da0566SAlex Crichton }
13686ec48545SAlex Crichton
13696ec48545SAlex Crichton #[test]
13706ec48545SAlex Crichton #[cfg_attr(miri, ignore)]
instantiate_non_page_aligned_sizes() -> Result<()>13716ec48545SAlex Crichton fn instantiate_non_page_aligned_sizes() -> Result<()> {
13726ec48545SAlex Crichton let mut config = Config::new();
13736ec48545SAlex Crichton config.wasm_custom_page_sizes(true);
137448f4621fSAlex Crichton let mut cfg = crate::small_pool_config();
13756ec48545SAlex Crichton cfg.total_memories(1);
13766ec48545SAlex Crichton cfg.max_memory_size(761927);
13776ec48545SAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
13786ec48545SAlex Crichton let engine = Engine::new(&config)?;
13796ec48545SAlex Crichton
13806ec48545SAlex Crichton let module = Module::new(
13816ec48545SAlex Crichton &engine,
13826ec48545SAlex Crichton r#"
13836ec48545SAlex Crichton (module
13846ec48545SAlex Crichton (memory 761927 761927 (pagesize 0x1))
13856ec48545SAlex Crichton )
13866ec48545SAlex Crichton "#,
13876ec48545SAlex Crichton )?;
13886ec48545SAlex Crichton let mut store = Store::new(&engine, ());
13896ec48545SAlex Crichton Instance::new(&mut store, &module, &[])?;
13906ec48545SAlex Crichton Ok(())
13916ec48545SAlex Crichton }
1392698028ceSAlex Crichton
1393698028ceSAlex Crichton #[test]
1394698028ceSAlex Crichton #[cfg_attr(miri, ignore)]
pagemap_scan_enabled_or_disabled() -> Result<()>1395698028ceSAlex Crichton fn pagemap_scan_enabled_or_disabled() -> Result<()> {
1396698028ceSAlex Crichton let mut config = Config::new();
1397698028ceSAlex Crichton let mut cfg = crate::small_pool_config();
1398698028ceSAlex Crichton cfg.total_memories(1);
1399698028ceSAlex Crichton cfg.pagemap_scan(Enabled::Yes);
1400698028ceSAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
1401698028ceSAlex Crichton let result = Engine::new(&config);
1402698028ceSAlex Crichton
1403698028ceSAlex Crichton if PoolingAllocationConfig::is_pagemap_scan_available() {
1404698028ceSAlex Crichton assert!(result.is_ok());
1405698028ceSAlex Crichton } else {
1406698028ceSAlex Crichton assert!(result.is_err());
1407698028ceSAlex Crichton }
1408698028ceSAlex Crichton Ok(())
1409698028ceSAlex Crichton }
1410509df0dfSAlex Crichton
1411*39e910beSAlex Crichton #[test]
1412*39e910beSAlex Crichton #[cfg_attr(miri, ignore)]
pooling_reuse_resets() -> Result<()>1413*39e910beSAlex Crichton fn pooling_reuse_resets() -> Result<()> {
1414*39e910beSAlex Crichton let mut config = Config::new();
1415*39e910beSAlex Crichton let mut cfg = crate::small_pool_config();
1416*39e910beSAlex Crichton cfg.total_memories(1);
1417*39e910beSAlex Crichton cfg.max_memory_size(0x2000000);
1418*39e910beSAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
1419*39e910beSAlex Crichton config.memory_guard_size(0);
1420*39e910beSAlex Crichton config.memory_reservation(0x2000000);
1421*39e910beSAlex Crichton let engine = Engine::new(&config)?;
1422*39e910beSAlex Crichton
1423*39e910beSAlex Crichton let a = Module::new(&engine, r#"(module (memory (export "m") 10 100))"#)?;
1424*39e910beSAlex Crichton let b = Module::new(
1425*39e910beSAlex Crichton &engine,
1426*39e910beSAlex Crichton r#"
1427*39e910beSAlex Crichton (module $B
1428*39e910beSAlex Crichton (memory 5 100)
1429*39e910beSAlex Crichton (func (export "read_oob") (result i32)
1430*39e910beSAlex Crichton (i32.load (i32.const 983040))
1431*39e910beSAlex Crichton )
1432*39e910beSAlex Crichton )
1433*39e910beSAlex Crichton "#,
1434*39e910beSAlex Crichton )?;
1435*39e910beSAlex Crichton
1436*39e910beSAlex Crichton {
1437*39e910beSAlex Crichton let mut store = Store::new(&engine, ());
1438*39e910beSAlex Crichton let instance = Instance::new(&mut store, &a, &[])?;
1439*39e910beSAlex Crichton let memory = instance.get_memory(&mut store, "m").unwrap();
1440*39e910beSAlex Crichton memory.grow(&mut store, 10)?;
1441*39e910beSAlex Crichton }
1442*39e910beSAlex Crichton
1443*39e910beSAlex Crichton {
1444*39e910beSAlex Crichton let mut store = Store::new(&engine, ());
1445*39e910beSAlex Crichton let instance = Instance::new(&mut store, &b, &[])?;
1446*39e910beSAlex Crichton let read_oob = instance.get_typed_func::<(), i32>(&mut store, "read_oob")?;
1447*39e910beSAlex Crichton let trap: Trap = read_oob.call(&mut store, ()).unwrap_err().downcast()?;
1448*39e910beSAlex Crichton assert_eq!(trap, Trap::MemoryOutOfBounds);
1449*39e910beSAlex Crichton }
1450*39e910beSAlex Crichton
1451*39e910beSAlex Crichton Ok(())
1452*39e910beSAlex Crichton }
1453*39e910beSAlex Crichton
1454509df0dfSAlex Crichton // This test instantiates a memory with an image into a slot in the pooling
1455509df0dfSAlex Crichton // allocator in a way that maps the image into the allocator but fails
1456509df0dfSAlex Crichton // instantiation. Failure here is injected with `ResourceLimiter`. Afterwards
1457509df0dfSAlex Crichton // instantiation is allowed to succeed with a memory that has no image, and this
1458509df0dfSAlex Crichton // asserts that the previous image is indeed not available any more as that
1459509df0dfSAlex Crichton // would otherwise mean data was leaked between modules.
1460509df0dfSAlex Crichton #[test]
memory_reset_if_instantiation_fails() -> Result<()>1461509df0dfSAlex Crichton fn memory_reset_if_instantiation_fails() -> Result<()> {
1462509df0dfSAlex Crichton struct Limiter;
1463509df0dfSAlex Crichton
1464509df0dfSAlex Crichton impl ResourceLimiter for Limiter {
1465509df0dfSAlex Crichton fn memory_growing(&mut self, _: usize, _: usize, _: Option<usize>) -> Result<bool> {
1466509df0dfSAlex Crichton Ok(false)
1467509df0dfSAlex Crichton }
1468509df0dfSAlex Crichton
1469509df0dfSAlex Crichton fn table_growing(&mut self, _: usize, _: usize, _: Option<usize>) -> Result<bool> {
1470509df0dfSAlex Crichton Ok(false)
1471509df0dfSAlex Crichton }
1472509df0dfSAlex Crichton }
1473509df0dfSAlex Crichton
1474509df0dfSAlex Crichton let pool = crate::small_pool_config();
1475509df0dfSAlex Crichton let mut config = Config::new();
1476509df0dfSAlex Crichton config.allocation_strategy(pool);
1477509df0dfSAlex Crichton let engine = Engine::new(&config)?;
1478509df0dfSAlex Crichton
1479509df0dfSAlex Crichton let module_with_image = Module::new(
1480509df0dfSAlex Crichton &engine,
1481509df0dfSAlex Crichton r#"
1482509df0dfSAlex Crichton (module
1483509df0dfSAlex Crichton (memory 1)
1484509df0dfSAlex Crichton (data (i32.const 0) "\aa")
1485509df0dfSAlex Crichton )
1486509df0dfSAlex Crichton "#,
1487509df0dfSAlex Crichton )?;
1488509df0dfSAlex Crichton let module_without_image = Module::new(
1489509df0dfSAlex Crichton &engine,
1490509df0dfSAlex Crichton r#"
1491509df0dfSAlex Crichton (module
1492509df0dfSAlex Crichton (memory (export "m") 1)
1493509df0dfSAlex Crichton )
1494509df0dfSAlex Crichton "#,
1495509df0dfSAlex Crichton )?;
1496509df0dfSAlex Crichton
1497509df0dfSAlex Crichton let mut store = Store::new(&engine, Limiter);
1498509df0dfSAlex Crichton store.limiter(|s| s);
1499509df0dfSAlex Crichton assert!(Instance::new(&mut store, &module_with_image, &[]).is_err());
1500509df0dfSAlex Crichton drop(store);
1501509df0dfSAlex Crichton
1502509df0dfSAlex Crichton let mut store = Store::new(&engine, Limiter);
1503509df0dfSAlex Crichton let instance = Instance::new(&mut store, &module_without_image, &[])?;
1504509df0dfSAlex Crichton let mem = instance.get_memory(&mut store, "m").unwrap();
1505509df0dfSAlex Crichton let data = mem.data(&store);
1506509df0dfSAlex Crichton assert_eq!(data[0], 0);
1507509df0dfSAlex Crichton
1508509df0dfSAlex Crichton Ok(())
1509509df0dfSAlex Crichton }
15108c22e58cSAlex Crichton
15118c22e58cSAlex Crichton #[test]
purge_module_with_mpk() -> Result<()>15128c22e58cSAlex Crichton fn purge_module_with_mpk() -> Result<()> {
15138c22e58cSAlex Crichton if !wasmtime::PoolingAllocationConfig::are_memory_protection_keys_available() {
15148c22e58cSAlex Crichton println!("skipping test; mpk is not supported");
15158c22e58cSAlex Crichton return Ok(());
15168c22e58cSAlex Crichton }
15178c22e58cSAlex Crichton
15188c22e58cSAlex Crichton let mut pool = crate::small_pool_config();
15198c22e58cSAlex Crichton pool.total_memories(2)
15208c22e58cSAlex Crichton .memory_protection_keys(Enabled::Yes)
15218c22e58cSAlex Crichton .max_memory_protection_keys(2);
15228c22e58cSAlex Crichton let mut config = Config::new();
15238c22e58cSAlex Crichton config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool));
15248c22e58cSAlex Crichton let engine = Engine::new(&config)?;
15258c22e58cSAlex Crichton
15268c22e58cSAlex Crichton // Create a module and instantiate it in stripe 0.
15278c22e58cSAlex Crichton let m1 = Module::new(&engine, "(module (memory 1))")?;
15288c22e58cSAlex Crichton let mut store = Store::new(&engine, ());
15298c22e58cSAlex Crichton Instance::new(&mut store, &m1, &[])?;
15308c22e58cSAlex Crichton
15318c22e58cSAlex Crichton // Create and instantiate a module in stripe 1. Note that the store is
15328c22e58cSAlex Crichton // immediately destroyed here after instantiation. That should leave the
15338c22e58cSAlex Crichton // linear memory slot available for re-instantiation.
15348c22e58cSAlex Crichton {
15358c22e58cSAlex Crichton let m2 = Module::new(&engine, "(module (memory 1))")?;
15368c22e58cSAlex Crichton Instance::new(&mut Store::new(&engine, ()), &m2, &[])?;
15378c22e58cSAlex Crichton
15388c22e58cSAlex Crichton // ... drop `m2` here which will purge it and should remove the warm
15398c22e58cSAlex Crichton // slot left for the module. Nothing should get corrupted...
15408c22e58cSAlex Crichton }
15418c22e58cSAlex Crichton
15428c22e58cSAlex Crichton // Drop the outer store here which will clean up the rest of the
15438c22e58cSAlex Crichton // instance/etc.
15448c22e58cSAlex Crichton drop(store);
15458c22e58cSAlex Crichton
15468c22e58cSAlex Crichton Ok(())
15478c22e58cSAlex Crichton }
1548