Repository: tetratelabs/wazero
Pull request #2085 (2024-02-21 01:04:22)

Changes Read to receive uint64 byte count.
Since #2074 changed the type of `Size() uint64` to we should probably change the type of `Read(offset uint32, byteCount uint64) ([]byte, bool)`. Otherwise, there's no API that gets entire buffer, if it covers the entire address range.

As discussed on [slack](https://gophers.slack.com/messages/C04CG4A2NKX/p1708414573291929?thread_ts=1708401526.868449).

mathetake: looking good. can you proceed?
ncruces: I got a bit stuck with the test failures, then work/life got in the way. Let me try again.
mathetake: yeah cool, no rush anyway! 

Patch:
diff --git a/api/wasm.go b/api/wasm.go
index 46d06a3c..6cb86e11 100644
--- a/api/wasm.go
+++ b/api/wasm.go
@@ -635,7 +635,7 @@ type Memory interface {
 	// shared. Those who need a stable view must set Wasm memory min=max, or
 	// use wazero.RuntimeConfig WithMemoryCapacityPages to ensure max is always
 	// allocated.
-	Read(offset, byteCount uint32) ([]byte, bool)
+	Read(offset uint32, byteCount uint64) ([]byte, bool)
 
 	// WriteByte writes a single byte to the underlying buffer at the offset in or returns false if out of range.
 	WriteByte(offset uint32, v byte) bool
diff --git a/examples/allocation/rust/greet.go b/examples/allocation/rust/greet.go
index 3d19eec3..e416d6bd 100644
--- a/examples/allocation/rust/greet.go
+++ b/examples/allocation/rust/greet.go
@@ -91,7 +91,7 @@ func main() {
 	defer deallocate.Call(ctx, uint64(greetingPtr), uint64(greetingSize))
 
 	// The pointer is a linear memory offset, which is where we write the name.
-	if bytes, ok := mod.Memory().Read(greetingPtr, greetingSize); !ok {
+	if bytes, ok := mod.Memory().Read(greetingPtr, uint64(greetingSize)); !ok {
 		log.Panicf("Memory.Read(%d, %d) out of range of memory size %d",
 			greetingPtr, greetingSize, mod.Memory().Size())
 	} else {
@@ -100,7 +100,7 @@ func main() {
 }
 
 func logString(ctx context.Context, m api.Module, offset, byteCount uint32) {
-	buf, ok := m.Memory().Read(offset, byteCount)
+	buf, ok := m.Memory().Read(offset, uint64(byteCount))
 	if !ok {
 		log.Panicf("Memory.Read(%d, %d) out of range", offset, byteCount)
 	}
diff --git a/examples/allocation/tinygo/greet.go b/examples/allocation/tinygo/greet.go
index 22d76d64..fcebeb19 100644
--- a/examples/allocation/tinygo/greet.go
+++ b/examples/allocation/tinygo/greet.go
@@ -106,7 +106,7 @@ func main() {
 	}
 
 	// The pointer is a linear memory offset, which is where we write the name.
-	if bytes, ok := mod.Memory().Read(greetingPtr, greetingSize); !ok {
+	if bytes, ok := mod.Memory().Read(greetingPtr, uint64(greetingSize)); !ok {
 		log.Panicf("Memory.Read(%d, %d) out of range of memory size %d",
 			greetingPtr, greetingSize, mod.Memory().Size())
 	} else {
@@ -115,7 +115,7 @@ func main() {
 }
 
 func logString(_ context.Context, m api.Module, offset, byteCount uint32) {
-	buf, ok := m.Memory().Read(offset, byteCount)
+	buf, ok := m.Memory().Read(offset, uint64(byteCount))
 	if !ok {
 		log.Panicf("Memory.Read(%d, %d) out of range", offset, byteCount)
 	}
diff --git a/examples/allocation/zig/greet.go b/examples/allocation/zig/greet.go
index 467dc8e0..7ed6bac5 100644
--- a/examples/allocation/zig/greet.go
+++ b/examples/allocation/zig/greet.go
@@ -98,7 +98,7 @@ func run() error {
 	greetingPtr := uint32(ptrSize[0] >> 32)
 	greetingSize := uint32(ptrSize[0])
 	// The pointer is a linear memory offset, which is where we write the name.
-	if bytes, ok := mod.Memory().Read(greetingPtr, greetingSize); !ok {
+	if bytes, ok := mod.Memory().Read(greetingPtr, uint64(greetingSize)); !ok {
 		return fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
 			greetingPtr, greetingSize, mod.Memory().Size())
 	} else {
@@ -109,7 +109,7 @@ func run() error {
 }
 
 func logString(_ context.Context, m api.Module, offset, byteCount uint32) {
-	buf, ok := m.Memory().Read(offset, byteCount)
+	buf, ok := m.Memory().Read(offset, uint64(byteCount))
 	if !ok {
 		log.Panicf("Memory.Read(%d, %d) out of range", offset, byteCount)
 	}
diff --git a/imports/assemblyscript/assemblyscript.go b/imports/assemblyscript/assemblyscript.go
index 5cbe605b..8f2ac445 100644
--- a/imports/assemblyscript/assemblyscript.go
+++ b/imports/assemblyscript/assemblyscript.go
@@ -305,7 +305,7 @@ func readAssemblyScriptString(mem api.Memory, offset uint32) (string, bool) {
 	if !ok || byteCount%2 != 0 {
 		return "", false
 	}
-	buf, ok := mem.Read(offset, byteCount)
+	buf, ok := mem.Read(offset, uint64(byteCount))
 	if !ok {
 		return "", false
 	}
diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go
index 384036a2..7ae2aef9 100644
--- a/imports/wasi_snapshot_preview1/fs.go
+++ b/imports/wasi_snapshot_preview1/fs.go
@@ -800,13 +800,13 @@ func fdReadOrPread(mod api.Module, params []uint64, isPread bool) experimentalsy
 
 func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte) (nread int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
 	var nread uint32
-	iovsStop := iovsCount << 3 // iovsCount * 8
+	iovsStop := uint64(iovsCount) * 8
 	iovsBuf, ok := mem.Read(iovs, iovsStop)
 	if !ok {
 		return 0, experimentalsys.EFAULT
 	}
 
-	for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
+	for iovsPos := uint64(0); iovsPos < iovsStop; iovsPos += 8 {
 		offset := le.Uint32(iovsBuf[iovsPos:])
 		l := le.Uint32(iovsBuf[iovsPos+4:])
 
@@ -814,7 +814,7 @@ func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte
 			continue
 		}
 
-		b, ok := mem.Read(offset, l)
+		b, ok := mem.Read(offset, uint64(l))
 		if !ok {
 			return 0, experimentalsys.EFAULT
 		}
@@ -917,7 +917,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) experimenta
 		// ^^ yes this can overflow to negative, which means our implementation
 		// doesn't support writing greater than max int64 entries.
 
-		buf, ok := mem.Read(buf, bufToWrite)
+		buf, ok := mem.Read(buf, uint64(bufToWrite))
 		if !ok {
 			return experimentalsys.EFAULT
 		}
@@ -1284,17 +1284,17 @@ func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) experimenta
 
 func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byte) (n int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
 	var nwritten uint32
-	iovsStop := iovsCount << 3 // iovsCount * 8
+	iovsStop := uint64(iovsCount) * 8
 	iovsBuf, ok := mem.Read(iovs, iovsStop)
 	if !ok {
 		return 0, experimentalsys.EFAULT
 	}
 
-	for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
+	for iovsPos := uint64(0); iovsPos < iovsStop; iovsPos += 8 {
 		offset := le.Uint32(iovsBuf[iovsPos:])
 		l := le.Uint32(iovsBuf[iovsPos+4:])
 
-		b, ok := mem.Read(offset, l)
+		b, ok := mem.Read(offset, uint64(l))
 		if !ok {
 			return 0, experimentalsys.EFAULT
 		}
@@ -1645,7 +1645,7 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) experimental
 // See https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/libc-bottom-half/sources/at_fdcwd.c
 // See https://linux.die.net/man/2/openat
 func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (experimentalsys.FS, string, experimentalsys.Errno) {
-	b, ok := mem.Read(p, pathLen)
+	b, ok := mem.Read(p, uint64(pathLen))
 	if !ok {
 		return nil, "", experimentalsys.EFAULT
 	}
@@ -1946,12 +1946,12 @@ func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) experimen
 		return experimentalsys.EINVAL
 	}
 
-	oldPathBuf, ok := mem.Read(oldPath, oldPathLen)
+	oldPathBuf, ok := mem.Read(oldPath, uint64(oldPathLen))
 	if !ok {
 		return experimentalsys.EFAULT
 	}
 
-	newPathBuf, ok := mem.Read(newPath, newPathLen)
+	newPathBuf, ok := mem.Read(newPath, uint64(newPathLen))
 	if !ok {
 		return experimentalsys.EFAULT
 	}
diff --git a/imports/wasi_snapshot_preview1/poll.go b/imports/wasi_snapshot_preview1/poll.go
index d09f3024..8c8839a5 100644
--- a/imports/wasi_snapshot_preview1/poll.go
+++ b/imports/wasi_snapshot_preview1/poll.go
@@ -62,11 +62,11 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno
 	mem := mod.Memory()
 
 	// Ensure capacity prior to the read loop to reduce error handling.
-	inBuf, ok := mem.Read(in, nsubscriptions*48)
+	inBuf, ok := mem.Read(in, uint64(nsubscriptions)*48)
 	if !ok {
 		return sys.EFAULT
 	}
-	outBuf, ok := mem.Read(out, nsubscriptions*32)
+	outBuf, ok := mem.Read(out, uint64(nsubscriptions)*32)
 	// zero-out all buffer before writing
 	for i := range outBuf {
 		outBuf[i] = 0
diff --git a/imports/wasi_snapshot_preview1/random.go b/imports/wasi_snapshot_preview1/random.go
index e4d7ccee..5c86968d 100644
--- a/imports/wasi_snapshot_preview1/random.go
+++ b/imports/wasi_snapshot_preview1/random.go
@@ -41,7 +41,7 @@ func randomGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
 	randSource := sysCtx.RandSource()
 	buf, bufLen := uint32(params[0]), uint32(params[1])
 
-	randomBytes, ok := mod.Memory().Read(buf, bufLen)
+	randomBytes, ok := mod.Memory().Read(buf, uint64(bufLen))
 	if !ok { // out-of-range
 		return sys.EFAULT
 	}
diff --git a/imports/wasi_snapshot_preview1/sock.go b/imports/wasi_snapshot_preview1/sock.go
index 756c0d39..291da486 100644
--- a/imports/wasi_snapshot_preview1/sock.go
+++ b/imports/wasi_snapshot_preview1/sock.go
@@ -85,7 +85,7 @@ func sockRecvFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
 		if !ok {
 			return sys.EINVAL
 		}
-		firstIovecBuf, ok := mem.Read(firstIovecBufAddr, firstIovecBufLen)
+		firstIovecBuf, ok := mem.Read(firstIovecBufAddr, uint64(firstIovecBufLen))
 		if !ok {
 			return sys.EINVAL
 		}
diff --git a/imports/wasi_snapshot_preview1/wasi.go b/imports/wasi_snapshot_preview1/wasi.go
index 4ef41d50..564ddf4c 100644
--- a/imports/wasi_snapshot_preview1/wasi.go
+++ b/imports/wasi_snapshot_preview1/wasi.go
@@ -233,12 +233,12 @@ func writeOffsetsAndNullTerminatedValues(mem api.Memory, values [][]byte, offset
 	// The caller may not place bytes directly after offsets, so we have to
 	// read them independently.
 	valuesLen := len(values)
-	offsetsLen := uint32(valuesLen * 4) // uint32Le
+	offsetsLen := uint64(valuesLen) * 4
 	offsetsBuf, ok := mem.Read(offsets, offsetsLen)
 	if !ok {
 		return sys.EFAULT
 	}
-	bytesBuf, ok := mem.Read(bytes, bytesLen)
+	bytesBuf, ok := mem.Read(bytes, uint64(bytesLen))
 	if !ok {
 		return sys.EFAULT
 	}
diff --git a/internal/logging/logging.go b/internal/logging/logging.go
index ecec61f7..2e1da2d5 100644
--- a/internal/logging/logging.go
+++ b/internal/logging/logging.go
@@ -263,7 +263,7 @@ func writeRef(_ context.Context, _ api.Module, w Writer, i uint32, vals []uint64
 
 func writeMemI32(_ context.Context, mod api.Module, w Writer, i uint32, vals []uint64) {
 	offset := uint32(vals[i])
-	byteCount := uint32(4)
+	byteCount := uint64(4)
 	if v, ok := mod.Memory().ReadUint32Le(offset); ok {
 		w.WriteString(strconv.FormatInt(int64(int32(v)), 10)) //nolint
 	} else { // log the positions that were out of memory
@@ -273,7 +273,7 @@ func writeMemI32(_ context.Context, mod api.Module, w Writer, i uint32, vals []u
 
 func writeMemH64(_ context.Context, mod api.Module, w Writer, i uint32, vals []uint64) {
 	offset := uint32(vals[i])
-	byteCount := uint32(8)
+	byteCount := uint64(8)
 	if s, ok := mod.Memory().Read(offset, byteCount); ok {
 		hex.NewEncoder(w).Write(s) //nolint
 	} else { // log the positions that were out of memory
@@ -283,10 +283,10 @@ func writeMemH64(_ context.Context, mod api.Module, w Writer, i uint32, vals []u
 
 func writeString(_ context.Context, mod api.Module, w Writer, i uint32, vals []uint64) {
 	offset, byteCount := uint32(vals[i]), uint32(vals[i+1])
-	WriteStringOrOOM(mod.Memory(), w, offset, byteCount)
+	WriteStringOrOOM(mod.Memory(), w, offset, uint64(byteCount))
 }
 
-func WriteStringOrOOM(mem api.Memory, w Writer, offset, byteCount uint32) {
+func WriteStringOrOOM(mem api.Memory, w Writer, offset uint32, byteCount uint64) {
 	if s, ok := mem.Read(offset, byteCount); ok {
 		w.Write(s) //nolint
 	} else { // log the positions that were out of memory
@@ -294,7 +294,7 @@ func WriteStringOrOOM(mem api.Memory, w Writer, offset, byteCount uint32) {
 	}
 }
 
-func WriteOOM(w Writer, offset uint32, byteCount uint32) {
+func WriteOOM(w Writer, offset uint32, byteCount uint64) {
 	w.WriteString("OOM(")                       //nolint
 	w.WriteString(strconv.Itoa(int(offset)))    //nolint
 	w.WriteByte(',')                            //nolint
diff --git a/internal/sysfs/osfile.go b/internal/sysfs/osfile.go
index a28ee6bb..490f0fa6 100644
--- a/internal/sysfs/osfile.go
+++ b/internal/sysfs/osfile.go
@@ -92,7 +92,7 @@ func (f *osFile) SetAppend(enable bool) (errno experimentalsys.Errno) {
 }
 
 // compile-time check to ensure osFile.reopen implements reopenFile.
-var _ reopenFile = (*fsFile)(nil).reopen
+var _ reopenFile = (*osFile)(nil).reopen
 
 func (f *osFile) reopen() (errno experimentalsys.Errno) {
 	// Clear any create flag, as we are re-opening, not re-creating.
diff --git a/internal/wasip1/logging/logging.go b/internal/wasip1/logging/logging.go
index d7341a09..7881f5e8 100644
--- a/internal/wasip1/logging/logging.go
+++ b/internal/wasip1/logging/logging.go
@@ -260,7 +260,7 @@ func (i logMemI64) Log(_ context.Context, mod api.Module, w logging.Writer, para
 type logFilestat uint32
 
 func (i logFilestat) Log(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
-	offset, byteCount := uint32(params[i]), uint32(64)
+	offset, byteCount := uint32(params[i]), uint64(64)
 	if buf, ok := mod.Memory().Read(offset, byteCount); ok {
 		w.WriteString("{filetype=")          //nolint
 		w.WriteString(FiletypeName(buf[16])) //nolint
@@ -275,7 +275,7 @@ func (i logFilestat) Log(_ context.Context, mod api.Module, w logging.Writer, pa
 type logFdstat uint32
 
 func (i logFdstat) Log(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
-	offset, byteCount := uint32(params[i]), uint32(24)
+	offset, byteCount := uint32(params[i]), uint64(24)
 	if buf, ok := mod.Memory().Read(offset, byteCount); ok {
 		w.WriteString("{filetype=")                           //nolint
 		w.WriteString(FiletypeName(buf[0]))                   //nolint
@@ -293,7 +293,7 @@ type logString uint32
 
 func (i logString) Log(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
 	offset, byteCount := uint32(params[i]), uint32(params[i+1])
-	if s, ok := mod.Memory().Read(offset, byteCount); ok {
+	if s, ok := mod.Memory().Read(offset, uint64(byteCount)); ok {
 		w.Write(s) //nolint
 	}
 }
diff --git a/internal/wasm/memory.go b/internal/wasm/memory.go
index 8deca519..5d549f8a 100644
--- a/internal/wasm/memory.go
+++ b/internal/wasm/memory.go
@@ -179,11 +179,11 @@ func (m *MemoryInstance) ReadFloat64Le(offset uint32) (float64, bool) {
 }
 
 // Read implements the same method as documented on api.Memory.
-func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
-	if !m.hasSize(offset, uint64(byteCount)) {
+func (m *MemoryInstance) Read(offset uint32, byteCount uint64) ([]byte, bool) {
+	if !m.hasSize(offset, byteCount) {
 		return nil, false
 	}
-	return m.Buffer[offset : offset+byteCount : offset+byteCount], true
+	return m.Buffer[offset : uint64(offset)+byteCount : uint64(offset)+byteCount], true
 }
 
 // WriteByte implements the same method as documented on api.Memory.


Test patch:
diff --git a/experimental/wazerotest/wazerotest.go b/experimental/wazerotest/wazerotest.go
index b5d865c9..252334b4 100644
--- a/experimental/wazerotest/wazerotest.go
+++ b/experimental/wazerotest/wazerotest.go
@@ -561,11 +561,11 @@ func (m *Memory) ReadFloat64Le(offset uint32) (float64, bool) {
 	return math.Float64frombits(v), ok
 }
 
-func (m *Memory) Read(offset, length uint32) ([]byte, bool) {
+func (m *Memory) Read(offset uint32, length uint64) ([]byte, bool) {
 	if m.isOutOfRange(offset, length) {
 		return nil, false
 	}
-	return m.Bytes[offset : offset+length : offset+length], true
+	return m.Bytes[offset : uint64(offset)+length : uint64(offset)+length], true
 }
 
 func (m *Memory) WriteByte(offset uint32, value byte) bool {
@@ -609,7 +609,7 @@ func (m *Memory) WriteFloat64Le(offset uint32, value float64) bool {
 }
 
 func (m *Memory) Write(offset uint32, value []byte) bool {
-	if m.isOutOfRange(offset, uint32(len(value))) {
+	if m.isOutOfRange(offset, uint64(len(value))) {
 		return false
 	}
 	copy(m.Bytes[offset:], value)
@@ -617,17 +617,16 @@ func (m *Memory) Write(offset uint32, value []byte) bool {
 }
 
 func (m *Memory) WriteString(offset uint32, value string) bool {
-	if m.isOutOfRange(offset, uint32(len(value))) {
+	if m.isOutOfRange(offset, uint64(len(value))) {
 		return false
 	}
 	copy(m.Bytes[offset:], value)
 	return true
 }
 
-func (m *Memory) isOutOfRange(_offset, _length uint32) bool {
-	size := int64(m.Size())
-	offset := int64(_offset)
-	length := int64(_length)
+func (m *Memory) isOutOfRange(_offset uint32, length uint64) bool {
+	size := m.Size()
+	offset := uint64(_offset)
 	return offset >= size || length > size || offset > (size-length)
 }
 
diff --git a/imports/wasi_snapshot_preview1/args_test.go b/imports/wasi_snapshot_preview1/args_test.go
index 42b048be..bbc6b00b 100644
--- a/imports/wasi_snapshot_preview1/args_test.go
+++ b/imports/wasi_snapshot_preview1/args_test.go
@@ -32,7 +32,7 @@ func Test_argsGet(t *testing.T) {
 <== errno=ESUCCESS
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(argvBuf-1, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(argvBuf-1, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
@@ -124,7 +124,7 @@ func Test_argsSizesGet(t *testing.T) {
 <== errno=ESUCCESS
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(resultArgc-1, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(resultArgc-1, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
diff --git a/imports/wasi_snapshot_preview1/clock_test.go b/imports/wasi_snapshot_preview1/clock_test.go
index 976f1055..dce231a0 100644
--- a/imports/wasi_snapshot_preview1/clock_test.go
+++ b/imports/wasi_snapshot_preview1/clock_test.go
@@ -63,7 +63,7 @@ func Test_clockResGet(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.ClockResGetName, uint64(tc.clockID), uint64(resultResolution))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(uint32(resultResolution-1), uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(uint32(resultResolution-1), uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -170,7 +170,7 @@ func Test_clockTimeGet(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.ClockTimeGetName, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(uint32(resultTimestamp-1), uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(uint32(resultTimestamp-1), uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
diff --git a/imports/wasi_snapshot_preview1/environ_test.go b/imports/wasi_snapshot_preview1/environ_test.go
index c981efc4..62a2d4c8 100644
--- a/imports/wasi_snapshot_preview1/environ_test.go
+++ b/imports/wasi_snapshot_preview1/environ_test.go
@@ -34,7 +34,7 @@ func Test_environGet(t *testing.T) {
 <== errno=ESUCCESS
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(resultEnvironBuf-1, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(resultEnvironBuf-1, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
@@ -128,7 +128,7 @@ func Test_environSizesGet(t *testing.T) {
 <== errno=ESUCCESS
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(resultEnvironc-1, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(resultEnvironc-1, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go
index 802a5fde..3d12f29d 100644
--- a/imports/wasi_snapshot_preview1/fs_test.go
+++ b/imports/wasi_snapshot_preview1/fs_test.go
@@ -380,7 +380,7 @@ func Test_fdFdstatGet(t *testing.T) {
 			requireErrnoResult(t, tc.expectedErrno, mod, wasip1.FdFdstatGetName, uint64(tc.fd), uint64(tc.resultFdstat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -472,7 +472,7 @@ func Test_fdFdstatGet_StdioNonblock(t *testing.T) {
 			requireErrnoResult(t, tc.expectedErrno, mod, wasip1.FdFdstatGetName, uint64(tc.fd), uint64(tc.resultFdstat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -822,7 +822,7 @@ func Test_fdFilestatGet(t *testing.T) {
 			requireErrnoResult(t, tc.expectedErrno, mod, wasip1.FdFilestatGetName, uint64(tc.fd), uint64(tc.resultFilestat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -1160,7 +1160,7 @@ func Test_fdPread(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdPreadName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(tc.offset), uint64(resultNread))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -1200,7 +1200,7 @@ func Test_fdPread_offset(t *testing.T) {
 	require.True(t, ok)
 
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdPreadName, uint64(fd), uint64(iovs), uint64(iovsCount), 2, uint64(resultNread))
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -1217,7 +1217,7 @@ func Test_fdPread_offset(t *testing.T) {
 	)
 
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdReadName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultNread))
-	actual, ok = mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok = mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -1388,7 +1388,7 @@ func Test_fdPrestatGet(t *testing.T) {
 <== (prestat={pr_name_len=1},errno=ESUCCESS)
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
@@ -1468,7 +1468,7 @@ func Test_fdPrestatDirName(t *testing.T) {
 <== (path=,errno=ESUCCESS)
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
@@ -1634,7 +1634,7 @@ func Test_fdPwrite(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdPwriteName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(tc.offset), uint64(resultNwritten))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 
@@ -1680,7 +1680,7 @@ func Test_fdPwrite_offset(t *testing.T) {
 
 	// Write the last half first, to offset 3
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdPwriteName, uint64(fd), uint64(iovs), uint64(iovsCount), 3, uint64(resultNwritten))
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -1704,7 +1704,7 @@ func Test_fdPwrite_offset(t *testing.T) {
 	require.True(t, ok)
 
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdWriteName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultNwritten))
-	actual, ok = mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok = mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -1895,7 +1895,7 @@ func Test_fdRead(t *testing.T) {
 <== (nread=6,errno=ESUCCESS)
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 }
@@ -2238,7 +2238,7 @@ func Test_fdReaddir(t *testing.T) {
 			require.True(t, ok)
 			require.Equal(t, tc.expectedBufused, bufused)
 
-			mem, ok := mod.Memory().Read(buf, bufused)
+			mem, ok := mod.Memory().Read(buf, uint64(bufused))
 			require.True(t, ok)
 
 			if tc.expectedMem != nil {
@@ -2621,7 +2621,7 @@ func Test_fdSeek(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdSeekName, uint64(fd), uint64(tc.offset), uint64(tc.whence), uint64(resultNewoffset))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 
@@ -2778,7 +2778,7 @@ func Test_fdTell(t *testing.T) {
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdTellName, uint64(fd), uint64(resultNewoffset))
 	require.Equal(t, expectedLog, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -2869,7 +2869,7 @@ func Test_fdWrite(t *testing.T) {
 <== (nwritten=6,errno=ESUCCESS)
 `, "\n"+log.String())
 
-	actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+	actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 	require.True(t, ok)
 	require.Equal(t, expectedMemory, actual)
 
@@ -3405,7 +3405,7 @@ func Test_pathFilestatGet(t *testing.T) {
 			requireErrnoResult(t, tc.expectedErrno, mod, wasip1.PathFilestatGetName, uint64(tc.fd), uint64(tc.flags), uint64(1), uint64(tc.pathLen), uint64(tc.resultFilestat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(tc.expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(tc.expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMemory, actual)
 		})
@@ -4277,7 +4277,7 @@ func Test_pathReadlink(t *testing.T) {
 
 				size, ok := mem.ReadUint32Le(resultBufused)
 				require.True(t, ok)
-				actual, ok := mem.Read(buf, size)
+				actual, ok := mem.Read(buf, uint64(size))
 				require.True(t, ok)
 				require.Equal(t, tc.expectedBuf, string(actual))
 			})
@@ -4990,7 +4990,7 @@ func Test_fdReaddir_dotEntryHasARealInode(t *testing.T) {
 
 	used, _ := mem.ReadUint32Le(resultBufused)
 
-	results, _ := mem.Read(buf, used)
+	results, _ := mem.Read(buf, uint64(used))
 	require.Equal(t, dirents, results)
 }
 
@@ -5059,7 +5059,7 @@ func Test_fdReaddir_opened_file_written(t *testing.T) {
 
 	used, _ := mem.ReadUint32Le(resultBufused)
 
-	results, _ := mem.Read(buf, used)
+	results, _ := mem.Read(buf, uint64(used))
 	require.Equal(t, dirents, results)
 }
 
diff --git a/imports/wasi_snapshot_preview1/poll_test.go b/imports/wasi_snapshot_preview1/poll_test.go
index a5357e79..d2735c35 100644
--- a/imports/wasi_snapshot_preview1/poll_test.go
+++ b/imports/wasi_snapshot_preview1/poll_test.go
@@ -55,7 +55,7 @@ func Test_pollOneoff(t *testing.T) {
 <== (nevents=1,errno=ESUCCESS)
 `, "\n"+log.String())
 
-	outMem, ok := mod.Memory().Read(out, uint32(len(expectedMem)))
+	outMem, ok := mod.Memory().Read(out, uint64(len(expectedMem)))
 	require.True(t, ok)
 	require.Equal(t, expectedMem, outMem)
 
@@ -136,7 +136,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 				uint64(tc.nsubscriptions), uint64(tc.resultNevents))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			out, ok := mod.Memory().Read(tc.out, uint32(len(tc.expectedMem)))
+			out, ok := mod.Memory().Read(tc.out, uint64(len(tc.expectedMem)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMem, out)
 
@@ -428,7 +428,7 @@ func Test_pollOneoff_Stdin(t *testing.T) {
 				uint64(tc.nsubscriptions), uint64(tc.resultNevents))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			out, ok := mod.Memory().Read(tc.out, uint32(len(tc.expectedMem)))
+			out, ok := mod.Memory().Read(tc.out, uint64(len(tc.expectedMem)))
 			require.True(t, ok)
 			require.Equal(t, tc.expectedMem, out)
 
@@ -492,7 +492,7 @@ func Test_pollOneoff_Zero(t *testing.T) {
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.PollOneoffName, uint64(0), uint64(out),
 		uint64(nsubscriptions), uint64(resultNevents))
 
-	outMem, ok := mod.Memory().Read(out, uint32(len(expectedMem)))
+	outMem, ok := mod.Memory().Read(out, uint64(len(expectedMem)))
 	require.True(t, ok)
 	require.Equal(t, expectedMem, outMem)
 
@@ -529,7 +529,7 @@ func Test_pollOneoff_Zero(t *testing.T) {
 	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.PollOneoffName, uint64(0), uint64(out),
 		uint64(nsubscriptions), uint64(resultNevents))
 
-	outMem, ok = mod.Memory().Read(out, uint32(len(expectedMem)))
+	outMem, ok = mod.Memory().Read(out, uint64(len(expectedMem)))
 	require.True(t, ok)
 	require.Equal(t, expectedMem, outMem)
 
diff --git a/imports/wasi_snapshot_preview1/random_test.go b/imports/wasi_snapshot_preview1/random_test.go
index 60bc1d84..d4364d60 100644
--- a/imports/wasi_snapshot_preview1/random_test.go
+++ b/imports/wasi_snapshot_preview1/random_test.go
@@ -22,13 +22,13 @@ func Test_randomGet(t *testing.T) {
 		'?', // stopped after encoding
 	}
 
-	length := uint32(5) // arbitrary length,
-	offset := uint32(1) // offset,
+	length := uint64(5) // arbitrary length,
+	offset := uint64(1) // offset,
 
 	maskMemory(t, mod, len(expectedMemory))
 
 	// Invoke randomGet and check the memory side effects!
-	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.RandomGetName, uint64(offset), uint64(length))
+	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.RandomGetName, offset, length)
 	require.Equal(t, `
 ==> wasi_snapshot_preview1.random_get(buf=1,buf_len=5)
 <== errno=ESUCCESS
diff --git a/imports/wasi_snapshot_preview1/sock_test.go b/imports/wasi_snapshot_preview1/sock_test.go
index 2bafbd37..b1d39183 100644
--- a/imports/wasi_snapshot_preview1/sock_test.go
+++ b/imports/wasi_snapshot_preview1/sock_test.go
@@ -275,7 +275,7 @@ func Test_sockRecv(t *testing.T) {
 			requireErrnoResult(t, tc.expectedErrno, mod, wasip1.SockRecvName, uint64(connFd), uint64(iovs), tc.iovsCount, uint64(tc.flags), uint64(resultRoDatalen), uint64(resultRoDatalen+4))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, expectedMemory, actual)
 		})
@@ -352,7 +352,7 @@ func Test_sockSend(t *testing.T) {
 			requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.SockSendName, uint64(connFd), uint64(iovs), uint64(iovsCount), 0, uint64(resultSoDatalen))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
-			actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
+			actual, ok := mod.Memory().Read(0, uint64(len(expectedMemory)))
 			require.True(t, ok)
 			require.Equal(t, expectedMemory, actual)
 
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index d8a238fd..5a9a5f67 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -1049,7 +1049,7 @@ func TestE2E_stores(t *testing.T) {
 
 	f := inst.ExportedFunction(testcases.ExportedFunctionName)
 
-	mem, ok := inst.Memory().Read(0, wasm.MemoryPageSize)
+	mem, ok := inst.Memory().Read(0, uint64(wasm.MemoryPageSize))
 	require.True(t, ok)
 	for _, tc := range []struct {
 		i32 uint32
diff --git a/internal/integration_test/engine/adhoc_test.go b/internal/integration_test/engine/adhoc_test.go
index 3147e3eb..694adf22 100644
--- a/internal/integration_test/engine/adhoc_test.go
+++ b/internal/integration_test/engine/adhoc_test.go
@@ -1055,7 +1055,7 @@ func testCall(t *testing.T, r wazero.Runtime) {
 // * Wasm code calls wasm.OpcodeMemoryGrowName and this changes the capacity (by default, it will).
 func testModuleMemory(t *testing.T, r wazero.Runtime) {
 	wasmPhrase := "Well, that'll be the day when you say goodbye."
-	wasmPhraseSize := uint32(len(wasmPhrase))
+	wasmPhraseSize := uint64(len(wasmPhrase))
 
 	one := uint32(1)
 
@@ -1109,7 +1109,7 @@ func testModuleMemory(t *testing.T, r wazero.Runtime) {
 	require.Equal(t, wasmPhrase, string(buf))
 
 	hostPhrase := "Goodbye, cruel world. I'm off to join the circus." // Intentionally slightly longer.
-	hostPhraseSize := uint32(len(hostPhrase))
+	hostPhraseSize := uint64(len(hostPhrase))
 
 	// Copy over the buffer, which should stop at the current length.
 	copy(buf, hostPhrase)
diff --git a/internal/integration_test/vs/runtime.go b/internal/integration_test/vs/runtime.go
index 2c2a7b4e..8964ee4b 100644
--- a/internal/integration_test/vs/runtime.go
+++ b/internal/integration_test/vs/runtime.go
@@ -82,7 +82,7 @@ func (m *wazeroModule) Memory() []byte {
 func (r *wazeroRuntime) log(_ context.Context, mod api.Module, stack []uint64) {
 	offset, byteCount := uint32(stack[0]), uint32(stack[1])
 
-	buf, ok := mod.Memory().Read(offset, byteCount)
+	buf, ok := mod.Memory().Read(offset, uint64(byteCount))
 	if !ok {
 		panic("out of memory reading log buffer")
 	}