Skip to content

Commit

Permalink
Set Memory.Max to min(user-memory-limit, sys-memory-limit) on load
Browse files Browse the repository at this point in the history
Updated `newMemorySizer()` to return the updated value, but also
ensure that an invalid `max` still throws an error (invalid module).

- Minor cleanup to use the `memorySizer` type instead of the full
  func signature for clarity
- Added a wat+wasm under `internal/integration_test/vs/testdata/`
  simply because that's where the other cache-related testdata was.

Closes tetratelabs#1152.

Signed-off-by: Edoardo Vacchi <[email protected]>
  • Loading branch information
evacchi committed Feb 24, 2023
1 parent d5c321e commit 5ea39f2
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 12 deletions.
34 changes: 34 additions & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import (
//go:embed internal/integration_test/vs/testdata/fac.wasm
var facWasm []byte

//go:embed internal/integration_test/vs/testdata/mem_grow.wasm
var memGrowWasm []byte

func TestCompilationCache(t *testing.T) {
ctx := context.Background()
// Ensures the normal Wasm module compilation cache works.
Expand Down Expand Up @@ -81,6 +84,37 @@ func TestCompilationCache(t *testing.T) {
// Ensures they are different.
require.NotEqual(t, fooCompiled, barCompiled)
})

t.Run("memory limit should not affect caches", func(t *testing.T) {
// Creates new cache instance and pass it to the config.
c := NewCompilationCache()
config := NewRuntimeConfig().WithCompilationCache(c)

// create two different runtimes with separate memory limits
rt0 := NewRuntimeWithConfig(ctx, config)
rt1 := NewRuntimeWithConfig(ctx, config.WithMemoryLimitPages(2))
rt2 := NewRuntimeWithConfig(ctx, config.WithMemoryLimitPages(4))

// the compiled module is not equal because the memory limits are applied to the Memory instance
module0, _ := rt0.CompileModule(ctx, memGrowWasm)
module1, _ := rt1.CompileModule(ctx, memGrowWasm)
module2, _ := rt2.CompileModule(ctx, memGrowWasm)

max0, _ := module0.ExportedMemories()["memory"].Max()
max1, _ := module1.ExportedMemories()["memory"].Max()
max2, _ := module2.ExportedMemories()["memory"].Max()
require.Equal(t, uint32(5), max0)
require.Equal(t, uint32(2), max1)
require.Equal(t, uint32(4), max2)

compiledModule0 := module0.(*compiledModule)
compiledModule1 := module1.(*compiledModule)
compiledModule2 := module2.(*compiledModule)

// compare the compiled engine which contains the underlying "codes"
require.Equal(t, compiledModule0.compiledEngine, compiledModule1.compiledEngine)
require.Equal(t, compiledModule1.compiledEngine, compiledModule2.compiledEngine)
})
}

func getCacheSharedRuntimes(ctx context.Context, t *testing.T) (foo, bar *runtime) {
Expand Down
Binary file added internal/integration_test/vs/testdata/mem_grow.wasm
Binary file not shown.
14 changes: 14 additions & 0 deletions internal/integration_test/vs/testdata/mem_grow.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(module
(memory (export "memory") 1 5) ;; start with one memory page, and max of 4 pages
(func $main

(loop $my_loop
(i32.gt_s
(memory.grow (i32.const 1))
(i32.const 0))
br_if $my_loop
unreachable)
return
)
(start $main)
)
8 changes: 8 additions & 0 deletions internal/wasm/binary/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ func newMemorySizer(memoryLimitPages uint32, memoryCapacityFromMax bool) memoryS
if memoryCapacityFromMax {
return minPages, *maxPages, *maxPages
}
// This is an invalid value: let it propagate, we will fail later.
if *maxPages > wasm.MemoryLimitPages {
return minPages, minPages, *maxPages
}
// This is a valid value, but it goes over the run-time limit: return the limit.
if *maxPages > memoryLimitPages {
return minPages, memoryLimitPages, memoryLimitPages
}
return minPages, minPages, *maxPages
}
return minPages, minPages, memoryLimitPages
Expand Down
2 changes: 1 addition & 1 deletion internal/wasm/binary/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func decodeImport(
r *bytes.Reader,
idx uint32,
memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
memorySizer memorySizer,
memoryLimitPages uint32,
enabledFeatures api.CoreFeatures,
) (i *wasm.Import, err error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/wasm/binary/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-memory
func decodeMemory(
r *bytes.Reader,
memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
memorySizer memorySizer,
memoryLimitPages uint32,
) (*wasm.Memory, error) {
min, maxP, err := decodeLimitsType(r)
Expand Down
36 changes: 28 additions & 8 deletions internal/wasm/binary/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,22 @@ func TestMemoryType(t *testing.T) {
max := wasm.MemoryLimitPages

tests := []struct {
name string
input *wasm.Memory
expected []byte
name string
input *wasm.Memory
wzmax uint32
expectedDecoded *wasm.Memory
expected []byte
}{
{
name: "min 0",
input: &wasm.Memory{Max: max, IsMaxEncoded: true},
expected: []byte{0x1, 0, 0x80, 0x80, 0x4},
},
{
name: "min 0 default max",
input: &wasm.Memory{Max: max},
expected: []byte{0x0, 0},
name: "min 0 default max",
input: &wasm.Memory{Max: max},
expectedDecoded: &wasm.Memory{Max: max},
expected: []byte{0x0, 0},
},
{
name: "min 0, max 0",
Expand All @@ -122,6 +125,13 @@ func TestMemoryType(t *testing.T) {
input: &wasm.Memory{Min: max, Cap: max, Max: max, IsMaxEncoded: true},
expected: []byte{0x1, 0x80, 0x80, 0x4, 0x80, 0x80, 0x4},
},
{
name: "min 0, max largest, wazero limit",
input: &wasm.Memory{Max: max, IsMaxEncoded: true},
wzmax: 512,
expectedDecoded: &wasm.Memory{Max: 512, Cap: 512, IsMaxEncoded: true},
expected: []byte{0x1, 0, 0x80, 0x80, 0x4},
},
}

for _, tt := range tests {
Expand All @@ -133,9 +143,19 @@ func TestMemoryType(t *testing.T) {
})

t.Run(fmt.Sprintf("decode %s", tc.name), func(t *testing.T) {
binary, err := decodeMemory(bytes.NewReader(b), newMemorySizer(max, false), max)
tmax := max
if tc.wzmax != 0 {
tmax = tc.wzmax
}

expectedDecoded := tc.expectedDecoded
if expectedDecoded == nil {
expectedDecoded = tc.input
}

binary, err := decodeMemory(bytes.NewReader(b), newMemorySizer(tmax, false), tmax)
require.NoError(t, err)
require.Equal(t, binary, tc.input)
require.Equal(t, binary, expectedDecoded)
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/wasm/binary/section.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]*wa

func decodeImportSection(
r *bytes.Reader,
memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
memorySizer memorySizer,
memoryLimitPages uint32,
enabledFeatures api.CoreFeatures,
) ([]*wasm.Import, error) {
Expand Down Expand Up @@ -84,7 +84,7 @@ func decodeTableSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*w

func decodeMemorySection(
r *bytes.Reader,
memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
memorySizer memorySizer,
memoryLimitPages uint32,
) (*wasm.Memory, error) {
vs, _, err := leb128.DecodeUint32(r)
Expand Down

0 comments on commit 5ea39f2

Please sign in to comment.