From 4dc4b834ec410f96117070621e786e38fb28692d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 26 Aug 2026 15:21:33 -0700 Subject: [PATCH 1/3] fix --- src/ir/memory-utils.cpp | 14 ++++++++++--- src/support/stdckdint.h | 12 +++++++++++ test/lit/ctor-eval/flatten_oob.wast | 32 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 test/lit/ctor-eval/flatten_oob.wast diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp index 6bbcf67a03d..6eb816ccc98 100644 --- a/src/ir/memory-utils.cpp +++ b/src/ir/memory-utils.cpp @@ -106,6 +106,14 @@ bool flatten(Module& wasm) { return false; } } + auto& memory = wasm.memories[0]; + uint64_t memoryInitialSizeBytes; + if (std::ckd_mul(&memoryInitialSizeBytes, + (uint64_t)memory->initial, + memory->pageSize())) { + return false; + } + for (auto& segment : dataSegments) { auto* offset = segment->offset->dynCast(); uint64_t start = offset->value.getUnsigned(); @@ -114,10 +122,10 @@ bool flatten(Module& wasm) { if (std::ckd_add(&end, start, size)) { return false; } + if (end > memoryInitialSizeBytes || end > MaxFlatMemorySize) { + return false; + } if (end > data.size()) { - if (end > MaxFlatMemorySize) { - return false; - } data.resize(end); } std::copy(segment->data.begin(), segment->data.end(), data.begin() + start); diff --git a/src/support/stdckdint.h b/src/support/stdckdint.h index c5132058332..f6ac4980345 100644 --- a/src/support/stdckdint.h +++ b/src/support/stdckdint.h @@ -46,6 +46,18 @@ template bool ckd_sub(T* output, T a, T b) { #endif } +template bool ckd_mul(T* output, T a, T b) { +#if __has_builtin(__builtin_mul_overflow) + return __builtin_mul_overflow(a, b, output); +#else + // Atm this polyfill only supports unsigned types. + static_assert(std::is_unsigned_v); + + *output = a * b; + return a != 0 && *output / a != b; +#endif +} + } // namespace std #endif // wasm_stdckdint_h diff --git a/test/lit/ctor-eval/flatten_oob.wast b/test/lit/ctor-eval/flatten_oob.wast new file mode 100644 index 00000000000..e0a63b355c8 --- /dev/null +++ b/test/lit/ctor-eval/flatten_oob.wast @@ -0,0 +1,32 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-ctor-eval %s --ctors=func --kept-exports=func --quiet -all -S -o - | filecheck %s + +;; The data segment here is at an offset that is out of bounds of the initial +;; memory. We should flatten memory here, as this traps anyhow, and we can +;; leave the module unchanged. + +(module + ;; CHECK: (type $0 (func (result i32))) + + ;; CHECK: (memory $0 16 17 shared) + (memory $0 16 17 shared) + + ;; CHECK: (data $0 (i32.const -1) "\00") + (data $0 (i32.const -1) "\00") + + ;; CHECK: (export "func" (func $0)) + (export "func" (func $func)) + + ;; CHECK: (func $0 (type $0) (result i32) + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $func (result i32) + ;; Use the memory to avoid it getting optimized out. + (i32.load + (i32.const 10) + ) + ) +) From 68cd6636d15ee39502037bbfec72e7247b4727c2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 26 Aug 2026 15:22:58 -0700 Subject: [PATCH 2/3] finish --- src/ir/memory-utils.cpp | 3 +++ test/lit/ctor-eval/flatten_oob.wast | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp index 6eb816ccc98..9cbadc92327 100644 --- a/src/ir/memory-utils.cpp +++ b/src/ir/memory-utils.cpp @@ -106,6 +106,9 @@ bool flatten(Module& wasm) { return false; } } + + // If we have more data than can fit in memory, we will trap anyhow, and it + // makes no sense to flatten. auto& memory = wasm.memories[0]; uint64_t memoryInitialSizeBytes; if (std::ckd_mul(&memoryInitialSizeBytes, diff --git a/test/lit/ctor-eval/flatten_oob.wast b/test/lit/ctor-eval/flatten_oob.wast index e0a63b355c8..2e32f3113e2 100644 --- a/test/lit/ctor-eval/flatten_oob.wast +++ b/test/lit/ctor-eval/flatten_oob.wast @@ -15,10 +15,10 @@ ;; CHECK: (data $0 (i32.const -1) "\00") (data $0 (i32.const -1) "\00") - ;; CHECK: (export "func" (func $0)) + ;; CHECK: (export "func" (func $func)) (export "func" (func $func)) - ;; CHECK: (func $0 (type $0) (result i32) + ;; CHECK: (func $func (type $0) (result i32) ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) From 574658006fcf533aadabcaf517a51af69e439962 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 26 Aug 2026 15:24:01 -0700 Subject: [PATCH 3/3] finish --- test/lit/ctor-eval/flatten_oob.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/ctor-eval/flatten_oob.wast b/test/lit/ctor-eval/flatten_oob.wast index 2e32f3113e2..75de283a0e0 100644 --- a/test/lit/ctor-eval/flatten_oob.wast +++ b/test/lit/ctor-eval/flatten_oob.wast @@ -3,7 +3,7 @@ ;; RUN: wasm-ctor-eval %s --ctors=func --kept-exports=func --quiet -all -S -o - | filecheck %s ;; The data segment here is at an offset that is out of bounds of the initial -;; memory. We should flatten memory here, as this traps anyhow, and we can +;; memory. We should not flatten memory here, as this traps anyhow, and we can ;; leave the module unchanged. (module