From b69b56b65a76c86f22d5375f6259e962f76642f7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Oct 2026 09:08:31 -0700 Subject: [PATCH 1/2] fix --- src/passes/OptimizeInstructions.cpp | 4 ++++ src/wasm-interpreter.h | 18 +++++++++++------- test/lit/exec/memory.grow-huge.wast | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 test/lit/exec/memory.grow-huge.wast diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 15926c65b64..2e0562f21b8 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1589,6 +1589,10 @@ struct OptimizeInstructions // Given the large amount of potential benefit we can get from a successful // optimization in GUFA, any reduction there may be a bad idea, so we // should be very careful and probably *not* remove such casts. + // + // The only case where we are always ok to remove such casts is when lastOpts + // is true, because nothing significant runs after us that can be harmed. That + // logic is in the StripRefiningCasts pass. // If an instruction traps on a null input, there is no need for a // ref.as_non_null on that input: we will trap either way (and the binaryen diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d5e358a081d..d4bd349b1b4 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -4616,14 +4616,18 @@ class ModuleRunnerBase : public ExpressionRunner { if (newSize > memory->max) { return fail; } - if (!info.interface()->growMemory( - info.name, (memorySize << pageSizeLog2), (newSize << pageSizeLog2))) { - // We failed to grow the memory in practice, even though it was valid - // to try to do so. - return fail; + // Only grow if we are actually changing the size (otherwise it is wasted + // work, and may OOM unnecessarily). + if (delta != 0) { + if (!info.interface()->growMemory( + info.name, (memorySize << pageSizeLog2), (newSize << pageSizeLog2))) { + // We failed to grow the memory in practice, even though it was valid + // to try to do so. + return fail; + } + memorySize = newSize; + info.instance->setMemorySize(info.name, memorySize); } - memorySize = newSize; - info.instance->setMemorySize(info.name, memorySize); return ret; } Flow visitMemoryInit(MemoryInit* curr) { diff --git a/test/lit/exec/memory.grow-huge.wast b/test/lit/exec/memory.grow-huge.wast new file mode 100644 index 00000000000..a14b5c3e14a --- /dev/null +++ b/test/lit/exec/memory.grow-huge.wast @@ -0,0 +1,19 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited. + +;; RUN: wasm-opt %s -all --fuzz-exec-before -q -o /dev/null 2>&1 | filecheck %s + +;; The memory here is over 2GB in size. We grow it by size 0, that is, just +;; retrieve the size without changing it. We should not error on an OOM here. + +(module + (memory i64 32769) + + ;; CHECK: [fuzz-exec] export measure + ;; CHECK-NEXT: [fuzz-exec] note result: measure => 32769 + (func $measure (export "measure") (result i64) + ;; This will return the size, 32769, and not -1 to indicate an OOM. + (memory.grow + (i64.const 0) + ) + ) +) From 2b9dd1200edb1ecdba152b72db4a0074c0f14ded Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Oct 2026 09:08:38 -0700 Subject: [PATCH 2/2] format --- src/wasm-interpreter.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d4bd349b1b4..733381f958f 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -4619,8 +4619,9 @@ class ModuleRunnerBase : public ExpressionRunner { // Only grow if we are actually changing the size (otherwise it is wasted // work, and may OOM unnecessarily). if (delta != 0) { - if (!info.interface()->growMemory( - info.name, (memorySize << pageSizeLog2), (newSize << pageSizeLog2))) { + if (!info.interface()->growMemory(info.name, + (memorySize << pageSizeLog2), + (newSize << pageSizeLog2))) { // We failed to grow the memory in practice, even though it was valid // to try to do so. return fail;