Skip to content

Commit

Permalink
Merge pull request #6 from ChainSafe/eclesio/uint64-size
Browse files Browse the repository at this point in the history
fix: Changes the type of Size() to uint64
  • Loading branch information
EclesioMeloJunior authored Mar 19, 2024
2 parents 4d11024 + 130c2d1 commit 78b21a5
Show file tree
Hide file tree
Showing 37 changed files with 253 additions and 153 deletions.
4 changes: 2 additions & 2 deletions api/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ type Memory interface {
// has 1 page: 65536
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-memorymathsfmemorysize%E2%91%A0
Size() uint32
Size() uint64

// Grow increases memory by the delta in pages (65536 bytes per page).
// The return val is the previous memory size in pages, or false if the
Expand Down Expand Up @@ -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
Expand Down
61 changes: 60 additions & 1 deletion builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package wazero

import (
"context"
"fmt"

"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/internal/wasm/binary"
)

// HostFunctionBuilder defines a host function (in Go), so that a
Expand Down Expand Up @@ -182,6 +184,35 @@ type HostFunctionBuilder interface {
type HostModuleBuilder interface {
// Note: until golang/go#5860, we can't use example tests to embed code in interface godocs.

// ExportMemory adds linear memory, which a WebAssembly module can import and become available via api.Memory.
// If a memory is already exported with the same name, this overwrites it.
//
// # Parameters
//
// - name - the name to export. Ex "memory" for wasi_snapshot_preview1.ModuleSnapshotPreview1
// - minPages - the possibly zero initial size in pages (65536 bytes per page).
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (memory (export "memory") 1)
// builder.ExportMemory(1)
//
// # Notes
//
// - This is allowed to grow to (4GiB) limited by api.MemorySizer. To bound it, use ExportMemoryWithMax.
// - Version 1.0 (20191205) of the WebAssembly spec allows at most one memory per module.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
ExportMemory(name string, minPages uint32) HostModuleBuilder

// ExportMemoryWithMax is like ExportMemory, but can prevent overuse of memory.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (memory (export "memory") 1 1)
// builder.ExportMemoryWithMax(1, 1)
//
// Note: api.MemorySizer determines the capacity.
ExportMemoryWithMax(name string, minPages, maxPages uint32) HostModuleBuilder

// NewFunctionBuilder begins the definition of a host function.
NewFunctionBuilder() HostFunctionBuilder

Expand Down Expand Up @@ -218,6 +249,7 @@ type hostModuleBuilder struct {
moduleName string
exportNames []string
nameToHostFunc map[string]*wasm.HostFunc
nameToMemory map[string]*wasm.Memory
}

// NewHostModuleBuilder implements Runtime.NewHostModuleBuilder
Expand All @@ -226,6 +258,7 @@ func (r *runtime) NewHostModuleBuilder(moduleName string) HostModuleBuilder {
r: r,
moduleName: moduleName,
nameToHostFunc: map[string]*wasm.HostFunc{},
nameToMemory: map[string]*wasm.Memory{},
}
}

Expand Down Expand Up @@ -299,6 +332,18 @@ func (h *hostFunctionBuilder) Export(exportName string) HostModuleBuilder {
return h.b
}

// ExportMemory implements ModuleBuilder.ExportMemory
func (b *hostModuleBuilder) ExportMemory(name string, minPages uint32) HostModuleBuilder {
b.nameToMemory[name] = &wasm.Memory{Min: minPages}
return b
}

// ExportMemoryWithMax implements ModuleBuilder.ExportMemoryWithMax
func (b *hostModuleBuilder) ExportMemoryWithMax(name string, minPages, maxPages uint32) HostModuleBuilder {
b.nameToMemory[name] = &wasm.Memory{Min: minPages, Max: maxPages, IsMaxEncoded: true}
return b
}

// ExportHostFunc implements wasm.HostFuncExporter
func (b *hostModuleBuilder) ExportHostFunc(fn *wasm.HostFunc) {
if _, ok := b.nameToHostFunc[fn.ExportName]; !ok { // add a new name
Expand All @@ -314,7 +359,19 @@ func (b *hostModuleBuilder) NewFunctionBuilder() HostFunctionBuilder {

// Compile implements HostModuleBuilder.Compile
func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error) {
module, err := wasm.NewHostModule(b.moduleName, b.exportNames, b.nameToHostFunc, b.r.enabledFeatures)
// Verify the maximum limit here, so we don't have to pass it to wasm.NewHostModule
for name, mem := range b.nameToMemory {
var maxP *uint32
if mem.IsMaxEncoded {
maxP = &mem.Max
}
mem.Min, mem.Cap, mem.Max = binary.NewMemorySizer(b.r.memoryLimitPages, b.r.memoryCapacityFromMax)(mem.Min, maxP)
if err := mem.Validate(b.r.memoryLimitPages); err != nil {
return nil, fmt.Errorf("memory[%s] %v", name, err)
}
}

module, err := wasm.NewHostModule(b.moduleName, b.exportNames, b.nameToHostFunc, b.nameToMemory, b.r.enabledFeatures)
if err != nil {
return nil, err
} else if err = module.Validate(b.r.enabledFeatures); err != nil {
Expand All @@ -327,6 +384,8 @@ func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error)
return nil, err
}

module.BuildMemoryDefinitions()

if err = b.r.store.Engine.CompileModule(ctx, module, listeners, false); err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions examples/allocation/rust/greet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions examples/allocation/tinygo/greet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions examples/allocation/zig/greet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down
15 changes: 8 additions & 7 deletions experimental/wazerotest/wazerotest.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ func (m *Memory) Definition() api.MemoryDefinition {
return memoryDefinition{memory: m}
}

func (m *Memory) Size() uint32 {
return uint32(len(m.Bytes))
func (m *Memory) Size() uint64 {
return uint64(len(m.Bytes))
}

func (m *Memory) Grow(deltaPages uint32) (previousPages uint32, ok bool) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -609,23 +609,24 @@ 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)
return true
}

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 {
func (m *Memory) isOutOfRange(_offset uint32, length uint64) bool {
size := m.Size()
offset := uint64(_offset)
return offset >= size || length > size || offset > (size-length)
}

Expand Down
2 changes: 1 addition & 1 deletion imports/assemblyscript/assemblyscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 4 additions & 4 deletions imports/wasi_snapshot_preview1/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -41,7 +41,7 @@ func Test_argsGet_Errors(t *testing.T) {
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithArgs("a", "bc"))
defer r.Close(testCtx)

memorySize := mod.Memory().Size()
memorySize := uint32(mod.Memory().Size())
validAddress := uint32(0) // arbitrary

tests := []struct {
Expand Down Expand Up @@ -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)
}
Expand All @@ -133,7 +133,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithArgs("a", "bc"))
defer r.Close(testCtx)

memorySize := mod.Memory().Size()
memorySize := uint32(mod.Memory().Size())
validAddress := uint32(0) // arbitrary valid address as arguments to args_sizes_get. We chose 0 here.

tests := []struct {
Expand Down
6 changes: 3 additions & 3 deletions imports/wasi_snapshot_preview1/clock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
Expand Down Expand Up @@ -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)
})
Expand Down Expand Up @@ -259,7 +259,7 @@ func Test_clockTimeGet_Errors(t *testing.T) {
mod, r, log := requireProxyModule(t, wazero.NewModuleConfig())
defer r.Close(testCtx)

memorySize := mod.Memory().Size()
memorySize := uint32(mod.Memory().Size())

tests := []struct {
name string
Expand Down
8 changes: 4 additions & 4 deletions imports/wasi_snapshot_preview1/environ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -44,7 +44,7 @@ func Test_environGet_Errors(t *testing.T) {
WithEnv("a", "bc").WithEnv("b", "cd"))
defer r.Close(testCtx)

memorySize := mod.Memory().Size()
memorySize := uint32(mod.Memory().Size())
validAddress := uint32(0) // arbitrary valid address as arguments to environ_get. We chose 0 here.

tests := []struct {
Expand Down Expand Up @@ -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)
}
Expand All @@ -138,7 +138,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
WithEnv("a", "b").WithEnv("b", "cd"))
defer r.Close(testCtx)

memorySize := mod.Memory().Size()
memorySize := uint32(mod.Memory().Size())
validAddress := uint32(0) // arbitrary

tests := []struct {
Expand Down
Loading

0 comments on commit 78b21a5

Please sign in to comment.