Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/passes/MemoryPacking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,15 +455,15 @@ void MemoryPacking::optimizeSegmentOps(Module* module) {
bool mustTrap = false;
auto* offset = curr->offset->dynCast<Const>();
auto* size = curr->size->dynCast<Const>();
if (offset && uint32_t(offset->value.geti32()) > maxRuntimeSize) {
if (offset && offset->value.getUnsigned() > maxRuntimeSize) {
mustTrap = true;
}
if (size && uint32_t(size->value.geti32()) > maxRuntimeSize) {
if (size && size->value.getUnsigned() > maxRuntimeSize) {
mustTrap = true;
}
if (offset && size) {
uint64_t offsetVal(offset->value.geti32());
uint64_t sizeVal(size->value.geti32());
auto offsetVal = offset->value.getUnsigned();
auto sizeVal = size->value.getUnsigned();
if (offsetVal + sizeVal > maxRuntimeSize) {
mustTrap = true;
} else if (offsetVal == 0 && sizeVal == 0) {
Expand Down Expand Up @@ -710,8 +710,8 @@ void MemoryPacking::createReplacements(Module* module,
}

// Nonconstant offsets or sizes will have inhibited splitting
size_t start = init->offset->cast<Const>()->value.geti32();
size_t end = start + init->size->cast<Const>()->value.geti32();
size_t start = init->offset->cast<Const>()->value.getUnsigned();
size_t end = start + init->size->cast<Const>()->value.getUnsigned();

// Index in `segments` of the segment used in emitted memory.init
// instructions
Expand Down
139 changes: 139 additions & 0 deletions test/lit/passes/memory-packing_memory64-high-addr.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt --memory-packing -all --zero-filled-memory -S -o - | filecheck %s
;; RUN: foreach %s %t wasm-opt --memory-packing -all --zero-filled-memory -tnh -S -o - | filecheck %s --check-prefix=TNH__

;; Test that memory-packing correctly handles memory64 data segment offsets
;; with the high bit set (>= 0x80000000). These must be treated as unsigned
;; values, not sign-extended to 64 bits.

(module
;; An active data segment at offset 0x80000000 on a memory64 with only 2
;; pages. The offset far exceeds the memory size, so this should trap and the
;; segment must be preserved.
;; CHECK: (memory $memory i64 2 2)
;; TNH__: (memory $memory i64 2 2)
(memory $memory i64 2 2)
;; CHECK: (data $data (i64.const 2147483648) "\00")
(data $data (i64.const 0x80000000) "\00")
)

(module
;; Similar to above but with a multi-byte segment that should be shortened to
;; a single byte at the highest address to preserve the trap.
;; CHECK: (memory $memory i64 2 2)
;; TNH__: (memory $memory i64 2 2)
(memory $memory i64 2 2)
;; CHECK: (data $data (i64.const 2147483650) "\00")
(data $data (i64.const 0x80000000) "\00\00\00")
)

(module
;; Offset 0xFFFFFFFF (4GB - 1) on memory64. This is a valid i64 offset that
;; must not be confused with -1 in i32. The segment should trap.
;; CHECK: (memory $memory i64 2 2)
;; TNH__: (memory $memory i64 2 2)
(memory $memory i64 2 2)
;; CHECK: (data $data (i64.const 4294967295) "\00")
(data $data (i64.const 0xFFFFFFFF) "\00")
)

(module
;; A memory64 with enough pages that offset 0x80000000 is in bounds (0x80000000
;; = 2GB, which is 32768 pages). The segment should be removable since it's all
;; zeroes and in bounds.
;; CHECK: (memory $memory i64 32769 32769)
;; TNH__: (memory $memory i64 32769 32769)
(memory $memory i64 32769 32769)
(data $data (i64.const 0x80000000) "\00")
)

(module
;; A passive segment used with memory.init. The memory.init offset into the
;; segment is 0x80000000 (as i32), which exceeds the segment data size and
;; should cause a trap. Ensure the i32 offset is treated as unsigned (2147483648)
;; not sign-extended to a negative value.
;; CHECK: (type $0 (func))

;; CHECK: (memory $memory i64 2 2)
;; TNH__: (type $0 (func))

;; TNH__: (memory $memory i64 2 2)
(memory $memory i64 2 2)
(data $data "hello")
;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const -2147483648)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; TNH__: (func $test (type $0)
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i64.const 0)
;; TNH__-NEXT: )
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i32.const -2147483648)
;; TNH__-NEXT: )
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i32.const 1)
;; TNH__-NEXT: )
;; TNH__-NEXT: (unreachable)
;; TNH__-NEXT: )
(func $test
(memory.init $data
(i64.const 0)
(i32.const 0x80000000)
(i32.const 1)
)
)
)

(module
;; A passive segment where memory.init size has the high bit set.
;; Size 0x80000000 (2147483648) exceeds the segment data size (5) and should
;; trap. Ensure the i32 size is treated as unsigned.
;; CHECK: (type $0 (func))

;; CHECK: (memory $memory i64 2 2)
;; TNH__: (type $0 (func))

;; TNH__: (memory $memory i64 2 2)
(memory $memory i64 2 2)
(data $data "hello")
;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const -2147483648)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; TNH__: (func $test (type $0)
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i64.const 0)
;; TNH__-NEXT: )
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i32.const 0)
;; TNH__-NEXT: )
;; TNH__-NEXT: (drop
;; TNH__-NEXT: (i32.const -2147483648)
;; TNH__-NEXT: )
;; TNH__-NEXT: (unreachable)
;; TNH__-NEXT: )
(func $test
(memory.init $data
(i64.const 0)
(i32.const 0)
(i32.const 0x80000000)
)
)
)
Loading