()
| 428 | #[test] |
| 429 | #[cfg_attr(miri, ignore)] |
| 430 | fn test_custom_memory_limiter() -> Result<()> { |
| 431 | let engine = Engine::default(); |
| 432 | let mut linker = Linker::new(&engine); |
| 433 | |
| 434 | // This approximates a function that would "allocate" resources that the host tracks. |
| 435 | // Here this is a simple function that increments the current host memory "used". |
| 436 | linker.func_wrap( |
| 437 | "", |
| 438 | "alloc", |
| 439 | |mut caller: Caller<'_, MemoryContext>, size: u32| -> u32 { |
| 440 | let ctx = caller.data_mut(); |
| 441 | let size = size as usize; |
| 442 | |
| 443 | if size + ctx.host_memory_used + ctx.wasm_memory_used <= ctx.memory_limit { |
| 444 | ctx.host_memory_used += size; |
| 445 | return 1; |
| 446 | } |
| 447 | |
| 448 | ctx.limit_exceeded = true; |
| 449 | |
| 450 | 0 |
| 451 | }, |
| 452 | )?; |
| 453 | |
| 454 | let module = Module::new( |
| 455 | &engine, |
| 456 | 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))"#, |
| 457 | )?; |
| 458 | |
| 459 | let context = MemoryContext { |
| 460 | host_memory_used: 0, |
| 461 | wasm_memory_used: 0, |
| 462 | memory_limit: 1 << 20, // 16 wasm pages is the limit for both wasm + host memory |
| 463 | limit_exceeded: false, |
| 464 | }; |
| 465 | |
| 466 | let mut store = Store::new(&engine, context); |
| 467 | store.limiter(|s| s as &mut dyn ResourceLimiter); |
| 468 | let instance = linker.instantiate(&mut store, &module)?; |
| 469 | let memory = instance.get_memory(&mut store, "m").unwrap(); |
| 470 | |
| 471 | // Grow the memory by 640 KiB |
| 472 | memory.grow(&mut store, 3)?; |
| 473 | memory.grow(&mut store, 5)?; |
| 474 | memory.grow(&mut store, 2)?; |
| 475 | |
| 476 | assert!(!store.data().limit_exceeded); |
| 477 | |
| 478 | // Grow the host "memory" by 384 KiB |
| 479 | let f = instance.get_typed_func::<u32, u32>(&mut store, "f")?; |
| 480 | |
| 481 | assert_eq!(f.call(&mut store, 1 * 0x10000)?, 1); |
| 482 | assert_eq!(f.call(&mut store, 3 * 0x10000)?, 1); |
| 483 | assert_eq!(f.call(&mut store, 2 * 0x10000)?, 1); |
| 484 | |
| 485 | // Memory is at the maximum, but the limit hasn't been exceeded |
| 486 | assert!(!store.data().limit_exceeded); |
| 487 |
nothing calls this directly
no test coverage detected