()
| 542 | #[tokio::test] |
| 543 | #[cfg_attr(miri, ignore)] |
| 544 | async fn test_custom_memory_limiter_async() -> Result<()> { |
| 545 | let engine = Engine::default(); |
| 546 | let mut linker = Linker::new(&engine); |
| 547 | |
| 548 | // This approximates a function that would "allocate" resources that the host tracks. |
| 549 | // Here this is a simple function that increments the current host memory "used". |
| 550 | linker.func_wrap( |
| 551 | "", |
| 552 | "alloc", |
| 553 | |mut caller: Caller<'_, MemoryContext>, size: u32| -> u32 { |
| 554 | let ctx = caller.data_mut(); |
| 555 | let size = size as usize; |
| 556 | |
| 557 | if size + ctx.host_memory_used + ctx.wasm_memory_used <= ctx.memory_limit { |
| 558 | ctx.host_memory_used += size; |
| 559 | return 1; |
| 560 | } |
| 561 | |
| 562 | ctx.limit_exceeded = true; |
| 563 | |
| 564 | 0 |
| 565 | }, |
| 566 | )?; |
| 567 | |
| 568 | let module = Module::new( |
| 569 | &engine, |
| 570 | r#"(module (import "" "alloc" (func $alloc (param i32) (result i32))) (memory (export "m") 0) (func (export "f") (param i32) (result i32) local.get 0 call $alloc))"#, |
| 571 | )?; |
| 572 | |
| 573 | let context = MemoryContext { |
| 574 | host_memory_used: 0, |
| 575 | wasm_memory_used: 0, |
| 576 | memory_limit: 1 << 20, // 16 wasm pages is the limit for both wasm + host memory |
| 577 | limit_exceeded: false, |
| 578 | }; |
| 579 | |
| 580 | let mut store = Store::new(&engine, context); |
| 581 | store.limiter_async(|s| s as &mut dyn ResourceLimiterAsync); |
| 582 | let instance = linker.instantiate_async(&mut store, &module).await?; |
| 583 | let memory = instance.get_memory(&mut store, "m").unwrap(); |
| 584 | |
| 585 | // Grow the memory by 640 KiB |
| 586 | memory.grow_async(&mut store, 3).await?; |
| 587 | memory.grow_async(&mut store, 5).await?; |
| 588 | memory.grow_async(&mut store, 2).await?; |
| 589 | |
| 590 | assert!(!store.data().limit_exceeded); |
| 591 | |
| 592 | // Grow the host "memory" by 384 KiB |
| 593 | let f = instance.get_typed_func::<u32, u32>(&mut store, "f")?; |
| 594 | |
| 595 | assert_eq!(f.call_async(&mut store, 1 * 0x10000).await?, 1); |
| 596 | assert_eq!(f.call_async(&mut store, 3 * 0x10000).await?, 1); |
| 597 | assert_eq!(f.call_async(&mut store, 2 * 0x10000).await?, 1); |
| 598 | |
| 599 | // Memory is at the maximum, but the limit hasn't been exceeded |
| 600 | assert!(!store.data().limit_exceeded); |
| 601 |
nothing calls this directly
no test coverage detected