From ae99d46d5aacce0cba46e4b5b65b161c60d49717 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2026 13:18:55 -0700 Subject: [PATCH] Further refine behavior of large 1-byte-page memories This commit adjust the behavior of #12884 to return -1 from `memory.grow` instead of trapping when the growth would exceed the maximal allowable size of memory. This fixes a fuzz-bug which had an unexpected trap and upon further reflection this feels more accurate for what custom-page-sizes can do. With a 1-byte-page memories can grow to 4GiB-2 because that means that -1 always means "growth failed". --- crates/wasmtime/src/runtime/vm/memory.rs | 17 ++++++++--------- .../custom-page-sizes/max-size-invalid.wast | 8 ++++---- tests/misc_testsuite/memory-combos.wast | 6 +++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/crates/wasmtime/src/runtime/vm/memory.rs b/crates/wasmtime/src/runtime/vm/memory.rs index df3919446765..09b6ff767d98 100644 --- a/crates/wasmtime/src/runtime/vm/memory.rs +++ b/crates/wasmtime/src/runtime/vm/memory.rs @@ -423,16 +423,15 @@ impl Memory { }); match new_size { Some(new_size) => { - // FIXME(WebAssembly/custom-page-sizes#45) - what should the - // behavior here be exactly? A trap? Return -1? A smaller limit? - // Unclear! - // - // Trap for now to make this as noisy/conservative as possible. + // Disallow growth to a value which this linear memory's type + // cannot represent. For example 1-byte-page memories cannot be + // 4GiB in size. if !self.ty().allow_growth_to(new_size) { - bail!( - "disallowing growth to {new_size:#x} bytes based on \ - page size" - ) + if let Some(limiter) = limiter { + let err = crate::format_err!("memory growth exceeds memory type's limits"); + limiter.memory_grow_failed(err)?; + } + return Ok(None); } } diff --git a/tests/misc_testsuite/custom-page-sizes/max-size-invalid.wast b/tests/misc_testsuite/custom-page-sizes/max-size-invalid.wast index cbc1f9d35d8d..d7cb36409534 100644 --- a/tests/misc_testsuite/custom-page-sizes/max-size-invalid.wast +++ b/tests/misc_testsuite/custom-page-sizes/max-size-invalid.wast @@ -26,8 +26,8 @@ memory.grow) ) -(assert_trap (invoke "grow" (i32.const 1)) "disallowing growth to 0xffffffff bytes based on page size") -(assert_trap (invoke "grow" (i32.const 2)) "disallowing growth to 0x100000000 bytes based on page size") -(assert_trap (invoke "grow" (i32.const 100)) "disallowing growth to 0x100000062 bytes based on page size") -(assert_trap (invoke "grow" (i32.const -1)) "disallowing growth to 0x1fffffffd bytes based on page size") +(assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) +(assert_return (invoke "grow" (i32.const 2)) (i32.const -1)) +(assert_return (invoke "grow" (i32.const 100)) (i32.const -1)) +(assert_return (invoke "grow" (i32.const -1)) (i32.const -1)) (assert_return (invoke "grow" (i32.const 0)) (i32.const -2)) diff --git a/tests/misc_testsuite/memory-combos.wast b/tests/misc_testsuite/memory-combos.wast index 74c209ee9452..0eb968fa7a02 100644 --- a/tests/misc_testsuite/memory-combos.wast +++ b/tests/misc_testsuite/memory-combos.wast @@ -127,7 +127,7 @@ (assert_trap (invoke "store_m3" (i32.const -1) (i32.const 0)) "out of bounds memory access") (assert_return (invoke "grow_m3" (i32.const 1)) (i32.const 1)) (assert_return (invoke "size_m3") (i32.const 2)) -(assert_trap (invoke "grow_m3" (i32.const -1)) "disallowing growth") +(assert_return (invoke "grow_m3" (i32.const -1)) (i32.const -1)) (assert_return (invoke "load_m3" (i32.const 1)) (i32.const 0)) (assert_return (invoke "store_m3" (i32.const 1) (i32.const 1))) (assert_return (invoke "load_m3" (i32.const 1)) (i32.const 1)) @@ -144,7 +144,7 @@ (assert_trap (invoke "store_m4" (i32.const -1) (i32.const 0)) "out of bounds memory access") (assert_return (invoke "grow_m4" (i32.const 1)) (i32.const 1)) (assert_return (invoke "size_m4") (i32.const 2)) -(assert_trap (invoke "grow_m4" (i32.const -1)) "disallowing growth") +(assert_return (invoke "grow_m4" (i32.const -1)) (i32.const -1)) (assert_return (invoke "load_m4" (i32.const 1)) (i32.const 0)) (assert_return (invoke "store_m4" (i32.const 1) (i32.const 1))) (assert_return (invoke "load_m4" (i32.const 1)) (i32.const 1)) @@ -178,7 +178,7 @@ (assert_trap (invoke "store_m8" (i32.const -1) (i32.const 0)) "out of bounds memory access") (assert_return (invoke "grow_m8" (i32.const 1)) (i32.const 1)) (assert_return (invoke "size_m8") (i32.const 2)) -(assert_trap (invoke "grow_m8" (i32.const -1)) "disallowing growth") +(assert_return (invoke "grow_m8" (i32.const -1)) (i32.const -1)) (assert_return (invoke "load_m8" (i32.const 1)) (i32.const 0)) (assert_return (invoke "store_m8" (i32.const 1) (i32.const 1))) (assert_return (invoke "load_m8" (i32.const 1)) (i32.const 1))