diff --git a/internal/engine/compiler/engine.go b/internal/engine/compiler/engine.go index e05f10a7..c1ac85fc 100644 --- a/internal/engine/compiler/engine.go +++ b/internal/engine/compiler/engine.go @@ -503,7 +503,7 @@ func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listene } // NewModuleEngine implements the same method as documented on wasm.Engine. -func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunctions, moduleFunctions []*wasm.FunctionInstance, tables []*wasm.TableInstance, tableInits []wasm.TableInitEntry) (wasm.ModuleEngine, error) { +func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunctions, moduleFunctions []*wasm.FunctionInstance) (wasm.ModuleEngine, error) { imported := len(importedFunctions) me := &moduleEngine{ name: name, @@ -528,19 +528,6 @@ func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunct function := c.createFunction(f) me.functions[imported+i] = function } - - for _, init := range tableInits { - references := tables[init.TableIndex].References - if int(init.Offset)+(len(init.FunctionIndexes)) > len(references) { - return me, wasm.ErrElementOffsetOutOfBounds - } - - for i, funcIdx := range init.FunctionIndexes { - if funcIdx != nil { - references[init.Offset+uint32(i)] = uintptr(unsafe.Pointer(me.functions[*funcIdx])) - } - } - } return me, nil } @@ -549,6 +536,11 @@ func (e *moduleEngine) Name() string { return e.name } +// FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine. +func (e *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Reference { + return uintptr(unsafe.Pointer(e.functions[funcIndex])) +} + // CreateFuncElementInstance implements the same method as documented on wasm.ModuleEngine. func (e *moduleEngine) CreateFuncElementInstance(indexes []*wasm.Index) *wasm.ElementInstance { refs := make([]wasm.Reference, len(indexes)) @@ -597,7 +589,7 @@ func (e *moduleEngine) NewCallEngine(callCtx *wasm.CallContext, f *wasm.Function // LookupFunction implements the same method as documented on wasm.ModuleEngine. func (e *moduleEngine) LookupFunction(t *wasm.TableInstance, typeId wasm.FunctionTypeID, tableOffset wasm.Index) (idx wasm.Index, err error) { - if tableOffset >= uint32(len(t.References)) { + if tableOffset >= uint32(len(t.References)) || t.Type != wasm.RefTypeFuncref { err = wasmruntime.ErrRuntimeInvalidTableAccess return } diff --git a/internal/engine/compiler/engine_test.go b/internal/engine/compiler/engine_test.go index 772060b6..a211c905 100644 --- a/internal/engine/compiler/engine_test.go +++ b/internal/engine/compiler/engine_test.go @@ -46,23 +46,6 @@ func (e *engineTester) NewEngine(enabledFeatures api.CoreFeatures) wasm.Engine { return newEngine(context.Background(), enabledFeatures) } -// InitTables implements the same method as documented on enginetest.EngineTester. -func (e engineTester) InitTables(me wasm.ModuleEngine, tableIndexToLen map[wasm.Index]int, tableInits []wasm.TableInitEntry) [][]wasm.Reference { - references := make([][]wasm.Reference, len(tableIndexToLen)) - for tableIndex, l := range tableIndexToLen { - references[tableIndex] = make([]uintptr, l) - } - internal := me.(*moduleEngine) - - for _, init := range tableInits { - referencesPerTable := references[init.TableIndex] - for idx, fnidx := range init.FunctionIndexes { - referencesPerTable[int(init.Offset)+idx] = uintptr(unsafe.Pointer(internal.functions[*fnidx])) - } - } - return references -} - // CompiledFunctionPointerValue implements the same method as documented on enginetest.EngineTester. func (e engineTester) CompiledFunctionPointerValue(me wasm.ModuleEngine, funcIndex wasm.Index) uint64 { internal := me.(*moduleEngine) @@ -78,11 +61,6 @@ func TestCompiler_Engine_InitializeFuncrefGlobals(t *testing.T) { enginetest.RunTestEngine_InitializeFuncrefGlobals(t, et) } -func TestCompiler_Engine_NewModuleEngine_InitTable(t *testing.T) { - requireSupportedOSArch(t) - enginetest.RunTestEngine_NewModuleEngine_InitTable(t, et) -} - func TestCompiler_ModuleEngine_LookupFunction(t *testing.T) { enginetest.RunTestModuleEngine_LookupFunction(t, et) } diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go index 1a1b9b66..511d9ae3 100644 --- a/internal/engine/interpreter/interpreter.go +++ b/internal/engine/interpreter/interpreter.go @@ -261,7 +261,7 @@ func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listene } // NewModuleEngine implements the same method as documented on wasm.Engine. -func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunctions, moduleFunctions []*wasm.FunctionInstance, tables []*wasm.TableInstance, tableInits []wasm.TableInitEntry) (wasm.ModuleEngine, error) { +func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunctions, moduleFunctions []*wasm.FunctionInstance) (wasm.ModuleEngine, error) { imported := uint32(len(importedFunctions)) me := &moduleEngine{ name: name, @@ -284,19 +284,6 @@ func (e *engine) NewModuleEngine(name string, module *wasm.Module, importedFunct insntantiatedcode := c.instantiate(f) me.functions = append(me.functions, insntantiatedcode) } - - for _, init := range tableInits { - references := tables[init.TableIndex].References - if int(init.Offset)+len(init.FunctionIndexes) > len(references) { - return me, wasm.ErrElementOffsetOutOfBounds - } - - for i, fnIndex := range init.FunctionIndexes { - if fnIndex != nil { - references[init.Offset+uint32(i)] = uintptr(unsafe.Pointer(me.functions[*fnIndex])) - } - } - } return me, nil } @@ -759,7 +746,7 @@ func (e *moduleEngine) CreateFuncElementInstance(indexes []*wasm.Index) *wasm.El } } -// InitializeFuncrefGlobals implements the same method as documented on wasm.InitializeFuncrefGlobals. +// InitializeFuncrefGlobals implements the same method as documented on wasm.ModuleEngine. func (e *moduleEngine) InitializeFuncrefGlobals(globals []*wasm.GlobalInstance) { for _, g := range globals { if g.Type.ValType == wasm.ValueTypeFuncref { @@ -773,6 +760,12 @@ func (e *moduleEngine) InitializeFuncrefGlobals(globals []*wasm.GlobalInstance) } } +// FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine. +func (e *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Reference { + return uintptr(unsafe.Pointer(e.functions[funcIndex])) +} + +// NewCallEngine implements the same method as documented on wasm.ModuleEngine. func (e *moduleEngine) NewCallEngine(callCtx *wasm.CallContext, f *wasm.FunctionInstance) (ce wasm.CallEngine, err error) { // Note: The input parameters are pre-validated, so a compiled function is only absent on close. Updates to // code on close aren't locked, neither is this read. diff --git a/internal/engine/interpreter/interpreter_test.go b/internal/engine/interpreter/interpreter_test.go index 9ae5890b..d9523499 100644 --- a/internal/engine/interpreter/interpreter_test.go +++ b/internal/engine/interpreter/interpreter_test.go @@ -89,23 +89,6 @@ func (e engineTester) NewEngine(enabledFeatures api.CoreFeatures) wasm.Engine { return NewEngine(context.Background(), enabledFeatures) } -// InitTables implements enginetest.EngineTester InitTables. -func (e engineTester) InitTables(me wasm.ModuleEngine, tableIndexToLen map[wasm.Index]int, tableInits []wasm.TableInitEntry) [][]wasm.Reference { - references := make([][]wasm.Reference, len(tableIndexToLen)) - for tableIndex, l := range tableIndexToLen { - references[tableIndex] = make([]wasm.Reference, l) - } - internal := me.(*moduleEngine) - - for _, init := range tableInits { - referencesPerTable := references[init.TableIndex] - for idx, fnidx := range init.FunctionIndexes { - referencesPerTable[int(init.Offset)+idx] = uintptr(unsafe.Pointer(internal.functions[*fnidx])) - } - } - return references -} - // CompiledFunctionPointerValue implements enginetest.EngineTester CompiledFunctionPointerValue. func (e engineTester) CompiledFunctionPointerValue(me wasm.ModuleEngine, funcIndex wasm.Index) uint64 { internal := me.(*moduleEngine) @@ -120,10 +103,6 @@ func TestInterpreter_Engine_InitializeFuncrefGlobals(t *testing.T) { enginetest.RunTestEngine_InitializeFuncrefGlobals(t, et) } -func TestInterpreter_Engine_NewModuleEngine_InitTable(t *testing.T) { - enginetest.RunTestEngine_NewModuleEngine_InitTable(t, et) -} - func TestInterpreter_ModuleEngine_LookupFunction(t *testing.T) { enginetest.RunTestModuleEngine_LookupFunction(t, et) } @@ -522,8 +501,6 @@ func TestInterpreter_Compile(t *testing.T) { &wasm.Module{}, nil, // imports nil, // moduleFunctions - nil, // table - nil, // tableInit ) require.EqualError(t, err, "source module for foo must be compiled before instantiation") }) diff --git a/internal/integration_test/bench/hostfunc_bench_test.go b/internal/integration_test/bench/hostfunc_bench_test.go index e26405fc..310cf3a2 100644 --- a/internal/integration_test/bench/hostfunc_bench_test.go +++ b/internal/integration_test/bench/hostfunc_bench_test.go @@ -194,7 +194,7 @@ func setupHostCallBench(requireNoError func(error)) *wasm.ModuleInstance { err := eng.CompileModule(testCtx, hostModule, nil) requireNoError(err) - hostME, err := eng.NewModuleEngine(host.Name, hostModule, nil, host.Functions, nil, nil) + hostME, err := eng.NewModuleEngine(host.Name, hostModule, nil, host.Functions) requireNoError(err) linkModuleToEngine(host, hostME) @@ -232,7 +232,7 @@ func setupHostCallBench(requireNoError func(error)) *wasm.ModuleInstance { importing.Functions = append([]*wasm.FunctionInstance{goFn, wasnFn}, importingFunctions...) importing.BuildExports(importingModule.ExportSection) - importingMe, err := eng.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{goFn, goReflectFn, wasnFn}, importingFunctions, nil, nil) + importingMe, err := eng.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{goFn, goReflectFn, wasnFn}, importingFunctions) requireNoError(err) linkModuleToEngine(importing, importingMe) diff --git a/internal/integration_test/fuzzcases/fuzzcases_test.go b/internal/integration_test/fuzzcases/fuzzcases_test.go index 355b541c..87398989 100644 --- a/internal/integration_test/fuzzcases/fuzzcases_test.go +++ b/internal/integration_test/fuzzcases/fuzzcases_test.go @@ -329,3 +329,10 @@ func Test733(t *testing.T) { }) }) } + +func Test873(t *testing.T) { + run(t, func(t *testing.T, r wazero.Runtime) { + _, err := r.InstantiateModuleFromBinary(ctx, getWasmBinary(t, 873)) + require.NoError(t, err) + }) +} diff --git a/internal/integration_test/fuzzcases/testdata/873.wasm b/internal/integration_test/fuzzcases/testdata/873.wasm new file mode 100644 index 00000000..c892da9f Binary files /dev/null and b/internal/integration_test/fuzzcases/testdata/873.wasm differ diff --git a/internal/integration_test/fuzzcases/testdata/873.wat b/internal/integration_test/fuzzcases/testdata/873.wat new file mode 100644 index 00000000..0c9b998b --- /dev/null +++ b/internal/integration_test/fuzzcases/testdata/873.wat @@ -0,0 +1,6 @@ +(module + (table (;0;) 34 553 externref) + (global (;0;) (mut i32) i32.const 1000) + (export "" (table 0)) + (elem (;0;) (i32.const -1) externref (ref.null extern) (ref.null extern)) +) diff --git a/internal/testing/enginetest/enginetest.go b/internal/testing/enginetest/enginetest.go index 8b11e3e6..f022cef6 100644 --- a/internal/testing/enginetest/enginetest.go +++ b/internal/testing/enginetest/enginetest.go @@ -40,8 +40,7 @@ var ( // testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors. testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary") // v_v is a nullary function type (void -> void) - v_v = &wasm.FunctionType{} - func1, func2 = wasm.Index(2), wasm.Index(1) + v_v = &wasm.FunctionType{} ) type EngineTester interface { @@ -52,10 +51,6 @@ type EngineTester interface { ListenerFactory() experimental.FunctionListenerFactory - // InitTables returns expected table contents ([]wasm.Reference) per table. - InitTables(me wasm.ModuleEngine, tableIndexToLen map[wasm.Index]int, - tableInits []wasm.TableInitEntry) [][]wasm.Reference - // CompiledFunctionPointerValue returns the opaque compiledFunction's pointer for the `funcIndex`. CompiledFunctionPointerValue(tme wasm.ModuleEngine, funcIndex wasm.Index) uint64 } @@ -64,7 +59,7 @@ func RunTestEngine_NewModuleEngine(t *testing.T, et EngineTester) { e := et.NewEngine(api.CoreFeaturesV1) t.Run("error before instantiation", func(t *testing.T) { - _, err := e.NewModuleEngine("mymod", &wasm.Module{}, nil, nil, nil, nil) + _, err := e.NewModuleEngine("mymod", &wasm.Module{}, nil, nil) require.EqualError(t, err, "source module for mymod must be compiled before instantiation") }) @@ -72,7 +67,7 @@ func RunTestEngine_NewModuleEngine(t *testing.T, et EngineTester) { m := &wasm.Module{} err := e.CompileModule(testCtx, m, nil) require.NoError(t, err) - me, err := e.NewModuleEngine(t.Name(), m, nil, nil, nil, nil) + me, err := e.NewModuleEngine(t.Name(), m, nil, nil) require.NoError(t, err) require.Equal(t, t.Name(), me.Name()) }) @@ -98,7 +93,7 @@ func RunTestEngine_InitializeFuncrefGlobals(t *testing.T, et EngineTester) { // To use the function, we first need to add it to a module. instance := &wasm.ModuleInstance{Name: t.Name(), TypeIDs: []wasm.FunctionTypeID{0}} fns := instance.BuildFunctions(m) - me, err := e.NewModuleEngine(t.Name(), m, nil, fns, nil, nil) + me, err := e.NewModuleEngine(t.Name(), m, nil, fns) require.NoError(t, err) nullRefVal := wasm.GlobalInstanceNullFuncRefValue @@ -151,7 +146,7 @@ func RunTestModuleEngine_Call(t *testing.T, et EngineTester) { module.Functions = module.BuildFunctions(m) // Compile the module - me, err := e.NewModuleEngine(module.Name, m, nil, module.Functions, nil, nil) + me, err := e.NewModuleEngine(module.Name, m, nil, module.Functions) require.NoError(t, err) linkModuleToEngine(module, me) @@ -182,252 +177,79 @@ func RunTestModuleEngine_Call(t *testing.T, et EngineTester) { }) } -func RunTestEngine_NewModuleEngine_InitTable(t *testing.T, et EngineTester) { - e := et.NewEngine(api.CoreFeaturesV1) - - t.Run("no table elements", func(t *testing.T) { - requireNewModuleEngine_emptyTable(t, e, et) - }) - t.Run("multi-table", func(t *testing.T) { - requireNewModuleEngine_multiTable(t, e, et) - }) - - t.Run("imported function", func(t *testing.T) { - requireNewModuleEngine_tableWithImportedFunction(t, e, et) - }) - - t.Run("mixed functions", func(t *testing.T) { - requireNewModuleEngine_tableWithMixedFunctions(t, e, et) - }) -} - -func requireNewModuleEngine_emptyTable(t *testing.T, e wasm.Engine, et EngineTester) (me wasm.ModuleEngine, module *wasm.ModuleInstance) { - tables := []*wasm.TableInstance{{Min: 2, References: make([]wasm.Reference, 2)}} - - // define a module with a function, but it isn't in the table. - m := &wasm.Module{ - TypeSection: []*wasm.FunctionType{v_v}, - FunctionSection: []wasm.Index{0}, - CodeSection: []*wasm.Code{{Body: []byte{wasm.OpcodeEnd}}}, - ID: wasm.ModuleID{0}, - } - m.BuildFunctionDefinitions() - err := e.CompileModule(testCtx, m, nil) - require.NoError(t, err) - - module = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}} - fns := module.BuildFunctions(m) - - // Instantiate the module, which has nothing but an empty table. - me, err = e.NewModuleEngine(t.Name(), m, nil, fns, tables, nil) - require.NoError(t, err) - - // Since there are no elements to initialize, we expect the table to be nil. - require.Equal(t, tables[0].References, make([]wasm.Reference, 2)) - - return -} - -// requireNewModuleEngine_multiTable ensures WebAssembly 2.0 multi-table feature works. -func requireNewModuleEngine_multiTable(t *testing.T, e wasm.Engine, et EngineTester) (me wasm.ModuleEngine, module *wasm.ModuleInstance) { - tables := []*wasm.TableInstance{ - {Min: 2, References: make([]wasm.Reference, 2)}, - {Min: 10, References: make([]wasm.Reference, 10)}, - } - - m := &wasm.Module{ - TypeSection: []*wasm.FunctionType{v_v}, - FunctionSection: []wasm.Index{0, 0, 0, 0}, - CodeSection: []*wasm.Code{ - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - }, - ID: wasm.ModuleID{1}, - } - m.BuildFunctionDefinitions() - err := e.CompileModule(testCtx, m, nil) - require.NoError(t, err) - - module = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}} - fns := module.BuildFunctions(m) - - tableInits := []wasm.TableInitEntry{ - {TableIndex: 0, Offset: 0, FunctionIndexes: []*wasm.Index{&func1}}, - {TableIndex: 1, Offset: 5, FunctionIndexes: []*wasm.Index{&func2}}, - } - - // Instantiate the module whose table points to its own functions. - me, err = e.NewModuleEngine(t.Name(), m, nil, fns, tables, tableInits) - require.NoError(t, err) - - // The functions mapped to the table are defined in the same moduleEngine - expectedTables := et.InitTables(me, map[wasm.Index]int{0: 2, 1: 10}, tableInits) - for idx, table := range tables { - require.Equal(t, expectedTables[idx], table.References) - } - - return -} - -func requireNewModuleEngine_tableWithImportedFunction(t *testing.T, e wasm.Engine, et EngineTester) (importingMe wasm.ModuleEngine, importing *wasm.ModuleInstance) { - tables := []*wasm.TableInstance{{Min: 2, References: make([]wasm.Reference, 2)}} - - importedModule := &wasm.Module{ - TypeSection: []*wasm.FunctionType{v_v}, - FunctionSection: []wasm.Index{0, 0, 0, 0}, - CodeSection: []*wasm.Code{ - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - }, - ID: wasm.ModuleID{2}, - } - importedModule.BuildFunctionDefinitions() - err := e.CompileModule(testCtx, importedModule, nil) - require.NoError(t, err) - - imported := &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}} - importedFunctions := imported.BuildFunctions(importedModule) - - // Imported functions are compiled before the importing module is instantiated. - importedMe, err := e.NewModuleEngine(t.Name(), importedModule, nil, importedFunctions, nil, nil) - require.NoError(t, err) - imported.Engine = importedMe - - // Instantiate the importing module, which is whose table is initialized. - importingModule := &wasm.Module{ - TypeSection: []*wasm.FunctionType{}, - FunctionSection: []wasm.Index{}, - CodeSection: []*wasm.Code{}, - ID: wasm.ModuleID{3}, - } - importingModule.BuildFunctionDefinitions() - err = e.CompileModule(testCtx, importingModule, nil) - require.NoError(t, err) - - tableInits := []wasm.TableInitEntry{ - {TableIndex: 0, Offset: 0, FunctionIndexes: []*wasm.Index{&func1}}, - } - - importing = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}} - fns := importing.BuildFunctions(importingModule) - - importingMe, err = e.NewModuleEngine(t.Name(), importingModule, importedFunctions, fns, tables, tableInits) - require.NoError(t, err) - - // A moduleEngine's compiled function slice includes its imports, so the offsets is absolute. - expectedTables := et.InitTables(importingMe, map[wasm.Index]int{0: 2}, tableInits) - for idx, table := range tables { - require.Equal(t, expectedTables[idx], table.References) - } - return -} - -func requireNewModuleEngine_tableWithMixedFunctions(t *testing.T, e wasm.Engine, et EngineTester) (importingMe wasm.ModuleEngine, importing *wasm.ModuleInstance) { - tables := []*wasm.TableInstance{{Min: 2, References: make([]wasm.Reference, 2)}} - - importedModule := &wasm.Module{ - TypeSection: []*wasm.FunctionType{v_v}, - FunctionSection: []wasm.Index{0, 0, 0, 0}, - CodeSection: []*wasm.Code{ - {Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}, - }, - ID: wasm.ModuleID{4}, - } - importedModule.BuildFunctionDefinitions() - err := e.CompileModule(testCtx, importedModule, nil) - require.NoError(t, err) - imported := &wasm.ModuleInstance{Name: t.Name(), TypeIDs: []wasm.FunctionTypeID{0}} - importedFunctions := imported.BuildFunctions(importedModule) - - // Imported functions are compiled before the importing module is instantiated. - importedMe, err := e.NewModuleEngine(t.Name(), importedModule, nil, importedFunctions, nil, nil) - require.NoError(t, err) - imported.Engine = importedMe - - importingModule := &wasm.Module{ - TypeSection: []*wasm.FunctionType{v_v}, - FunctionSection: []wasm.Index{0, 0, 0, 0}, - CodeSection: []*wasm.Code{ - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - {Body: []byte{wasm.OpcodeEnd}}, - }, - ID: wasm.ModuleID{5}, - } - importingModule.BuildFunctionDefinitions() - err = e.CompileModule(testCtx, importingModule, nil) - require.NoError(t, err) - - importing = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}} - fns := importing.BuildFunctions(importingModule) - - tableInits := []wasm.TableInitEntry{ - {TableIndex: 0, Offset: 0, FunctionIndexes: []*wasm.Index{&func1, &func2}}, - } - - // Instantiate the importing module, which is whose table is initialized. - importingMe, err = e.NewModuleEngine(t.Name(), importingModule, importedFunctions, fns, tables, tableInits) - require.NoError(t, err) - - // A moduleEngine's compiled function slice includes its imports, so the offsets are absolute. - expectedTables := et.InitTables(importingMe, map[wasm.Index]int{0: 2}, tableInits) - for idx, table := range tables { - require.Equal(t, expectedTables[idx], table.References) - } - - return -} - func RunTestModuleEngine_LookupFunction(t *testing.T, et EngineTester) { e := et.NewEngine(api.CoreFeaturesV1) - t.Run("no table elements", func(t *testing.T) { - me, m := requireNewModuleEngine_emptyTable(t, e, et) + mod := &wasm.Module{ + TypeSection: []*wasm.FunctionType{{}, {Params: []wasm.ValueType{wasm.ValueTypeV128}}}, + FunctionSection: []wasm.Index{0, 0, 0}, + CodeSection: []*wasm.Code{ + { + Body: []byte{wasm.OpcodeEnd}, + }, {Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}, + }, + } - _, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0 /* out of range */) + mod.BuildFunctionDefinitions() + err := e.CompileModule(testCtx, mod, nil) + require.NoError(t, err) + m := &wasm.ModuleInstance{TypeIDs: []wasm.FunctionTypeID{0, 1}} + m.Tables = []*wasm.TableInstance{ + {Min: 2, References: make([]wasm.Reference, 2), Type: wasm.RefTypeFuncref}, + {Min: 2, References: make([]wasm.Reference, 2), Type: wasm.RefTypeExternref}, + {Min: 10, References: make([]wasm.Reference, 10), Type: wasm.RefTypeFuncref}, + } + m.Functions = m.BuildFunctions(mod) + + me, err := e.NewModuleEngine(m.Name, mod, nil, m.Functions) + require.NoError(t, err) + linkModuleToEngine(m, me) + + t.Run("null reference", func(t *testing.T) { + _, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) // offset 0 is not initialized yet. + require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) + _, err = me.LookupFunction(m.Tables[0], m.TypeIDs[0], 1) // offset 1 is not initialized yet. require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) }) - t.Run("multi-table", func(t *testing.T) { - me, m := requireNewModuleEngine_multiTable(t, e, et) + m.Tables[0].References[0] = me.FunctionInstanceReference(2) + m.Tables[0].References[1] = me.FunctionInstanceReference(0) - // table[0][0] should point to func1 - idx, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) + t.Run("initialized", func(t *testing.T) { + index, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) // offset 0 is now initialized. require.NoError(t, err) - require.Equal(t, func1, idx) - - // table[1][5] should point to func2 - idx, err = me.LookupFunction(m.Tables[1], m.TypeIDs[0], 5) + require.Equal(t, wasm.Index(2), index) + index, err = me.LookupFunction(m.Tables[0], m.TypeIDs[0], 1) // offset 1 is now initialized. require.NoError(t, err) - require.Equal(t, func2, idx) + require.Equal(t, wasm.Index(0), index) }) - t.Run("imported function", func(t *testing.T) { - me, m := requireNewModuleEngine_tableWithImportedFunction(t, e, et) - - // table[0][0] should point to func1 - idx, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) - require.NoError(t, err) - require.Equal(t, func1, idx) + t.Run("out of range", func(t *testing.T) { + _, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 100 /* out of range */) + require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) }) - t.Run("mixed functions", func(t *testing.T) { - me, m := requireNewModuleEngine_tableWithMixedFunctions(t, e, et) + t.Run("access to externref table", func(t *testing.T) { + _, err := me.LookupFunction(m.Tables[1], /* table[1] has externref type. */ + m.TypeIDs[0], 0) + require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) + }) - // table[0][0] should point to func1 - idx, err := me.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) - require.NoError(t, err) - require.Equal(t, func1, idx) + t.Run("access to externref table", func(t *testing.T) { + _, err := me.LookupFunction(m.Tables[0], /* type mismatch */ + m.TypeIDs[1], 0) + require.Equal(t, wasmruntime.ErrRuntimeIndirectCallTypeMismatch, err) + }) - // table[0][1] should point to func2 - idx, err = me.LookupFunction(m.Tables[0], m.TypeIDs[0], 1) + m.Tables[2].References[0] = me.FunctionInstanceReference(1) + m.Tables[2].References[5] = me.FunctionInstanceReference(2) + t.Run("initialized - tables[2]", func(t *testing.T) { + index, err := me.LookupFunction(m.Tables[2], m.TypeIDs[0], 0) require.NoError(t, err) - require.Equal(t, func2, idx) + require.Equal(t, wasm.Index(1), index) + index, err = me.LookupFunction(m.Tables[2], m.TypeIDs[0], 5) + require.NoError(t, err) + require.Equal(t, wasm.Index(2), index) }) } @@ -700,7 +522,7 @@ func RunTestModuleEngine_Memory(t *testing.T, et EngineTester) { grow, init := module.Functions[0], module.Functions[1] // Compile the module - me, err := e.NewModuleEngine(module.Name, m, nil, module.Functions, nil, nil) + me, err := e.NewModuleEngine(module.Name, m, nil, module.Functions) require.NoError(t, err) linkModuleToEngine(module, me) @@ -831,7 +653,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime host.BuildExports(hostModule.ExportSection) hostFn := host.Exports[divByGoName].Function - hostME, err := e.NewModuleEngine(host.Name, hostModule, nil, host.Functions, nil, nil) + hostME, err := e.NewModuleEngine(host.Name, hostModule, nil, host.Functions) require.NoError(t, err) linkModuleToEngine(host, hostME) @@ -869,7 +691,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime callHostFn := imported.Exports[callDivByGoName].Function // Compile the imported module - importedMe, err := e.NewModuleEngine(imported.Name, importedModule, []*wasm.FunctionInstance{hostFn}, importedFunctions, nil, nil) + importedMe, err := e.NewModuleEngine(imported.Name, importedModule, []*wasm.FunctionInstance{hostFn}, importedFunctions) require.NoError(t, err) linkModuleToEngine(imported, importedMe) @@ -902,7 +724,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime importing.BuildExports(importingModule.ExportSection) // Compile the importing module - importingMe, err := e.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{callHostFn}, importingFunctions, nil, nil) + importingMe, err := e.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{callHostFn}, importingFunctions) require.NoError(t, err) linkModuleToEngine(importing, importingMe) @@ -950,7 +772,7 @@ func setupCallMemTests(t *testing.T, e wasm.Engine, readMem *wasm.Code, fnlf exp readMemFn := host.Exports[readMemName].Function callReadMemFn := host.Exports[callReadMemName].Function - hostME, err := e.NewModuleEngine(host.Name, hostModule, nil, host.Functions, nil, nil) + hostME, err := e.NewModuleEngine(host.Name, hostModule, nil, host.Functions) require.NoError(t, err) linkModuleToEngine(host, hostME) @@ -993,7 +815,7 @@ func setupCallMemTests(t *testing.T, e wasm.Engine, readMem *wasm.Code, fnlf exp importing.BuildExports(importingModule.ExportSection) // Compile the importing module - importingMe, err := e.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{readMemFn, callReadMemFn}, importingFunctions, nil, nil) + importingMe, err := e.NewModuleEngine(importing.Name, importingModule, []*wasm.FunctionInstance{readMemFn, callReadMemFn}, importingFunctions) require.NoError(t, err) linkModuleToEngine(importing, importingMe) diff --git a/internal/wasm/engine.go b/internal/wasm/engine.go index 80c3eef2..d7193510 100644 --- a/internal/wasm/engine.go +++ b/internal/wasm/engine.go @@ -2,7 +2,6 @@ package wasm import ( "context" - "errors" "github.com/tetratelabs/wazero/experimental" ) @@ -27,18 +26,10 @@ type Engine interface { // * module is the source module from which moduleFunctions are instantiated. This is used for caching. // * importedFunctions: functions this module imports, already compiled in this engine. // * moduleFunctions: functions declared in this module that must be compiled. - // * tables: possibly shared tables used by this module. When nil tableInit will be nil. - // * tableInit: a mapping of Table's index to a mapping of TableInstance.Table index to the function index it should point to. // // Note: Input parameters must be pre-validated with wasm.Module Validate, to ensure no fields are invalid // due to reasons such as out-of-bounds. - NewModuleEngine( - name string, - module *Module, - importedFunctions, moduleFunctions []*FunctionInstance, - tables []*TableInstance, - tableInits []TableInitEntry, - ) (ModuleEngine, error) + NewModuleEngine(name string, module *Module, importedFunctions, moduleFunctions []*FunctionInstance) (ModuleEngine, error) } // ModuleEngine implements function calls for a given module. @@ -58,6 +49,10 @@ type ModuleEngine interface { // InitializeFuncrefGlobals initializes the globals of Funcref type as the opaque pointer values of engine specific compiled functions. InitializeFuncrefGlobals(globals []*GlobalInstance) + + // FunctionInstanceReference returns Reference for the given Index for a FunctionInstance. The returned values are used by + // the initialization via ElementSegment. + FunctionInstanceReference(funcIndex Index) Reference } // CallEngine implements function calls for a FunctionInstance. It manages its own call frame stack and value stack, @@ -66,19 +61,3 @@ type CallEngine interface { // Call invokes a function instance f with given parameters. Call(ctx context.Context, m *CallContext, params []uint64) (results []uint64, err error) } - -// TableInitEntry is normalized element segment used for initializing tables by engines. -type TableInitEntry struct { - TableIndex Index - // Offset is the offset in the table from which the table is initialized by engine. - Offset Index - // FunctionIndexes contains nullable function indexes. - FunctionIndexes []*Index -} - -// ErrElementOffsetOutOfBounds is the error raised when the active element offset exceeds the table length. -// Before CoreFeatureReferenceTypes, this was checked statically before instantiation, after the proposal, -// this must be raised as runtime error (as in assert_trap in spectest), not even an instantiation error. -// -// See https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/linking.wast#L264-L274 -var ErrElementOffsetOutOfBounds = errors.New("element offset ouf of bounds") diff --git a/internal/wasm/store.go b/internal/wasm/store.go index 2d496bc8..8aab7e54 100644 --- a/internal/wasm/store.go +++ b/internal/wasm/store.go @@ -3,7 +3,6 @@ package wasm import ( "context" "encoding/binary" - "errors" "fmt" "sync" @@ -195,6 +194,35 @@ func (m *ModuleInstance) buildElementInstances(elements []*ElementSegment) { } } +func (m *ModuleInstance) applyTableInits(tables []*TableInstance, tableInits []tableInitEntry) { + for _, init := range tableInits { + table := tables[init.tableIndex] + references := table.References + if int(init.offset)+len(init.functionIndexes) > len(references) { + // ErrElementOffsetOutOfBounds is the error raised when the active element offset exceeds the table length. + // Before CoreFeatureReferenceTypes, this was checked statically before instantiation, after the proposal, + // this must be raised as runtime error (as in assert_trap in spectest), not even an instantiation error. + // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/linking.wast#L264-L274 + // + // In wazero, we ignore it since in any way, the instantiated module and engines are fine and can be used + // for function invocations. + return + } + + if table.Type == RefTypeExternref { + for i := 0; i < init.nullExternRefCount; i++ { + references[init.offset+uint32(i)] = Reference(0) + } + } else { + for i, fnIndex := range init.functionIndexes { + if fnIndex != nil { + references[init.offset+uint32(i)] = m.Engine.FunctionInstanceReference(*fnIndex) + } + } + } + } +} + func (m *ModuleInstance) BuildExports(exports []*Export) { m.Exports = make(map[string]*ExportInstance, len(exports)) for _, exp := range exports { @@ -367,12 +395,9 @@ func (s *Store) instantiate( } // Plus, we are ready to compile functions. - m.Engine, err = s.Engine.NewModuleEngine(name, module, importedFunctions, functions, tables, tableInit) - if err != nil && !errors.Is(err, ErrElementOffsetOutOfBounds) { - // ErrElementOffsetOutOfBounds is not an instantiation error, but rather runtime error, so we ignore it as - // in anyway the instantiated module and engines are fine and can be used for function invocations. - // See comments on ErrElementOffsetOutOfBounds. - return nil, fmt.Errorf("compilation failed: %w", err) + m.Engine, err = s.Engine.NewModuleEngine(name, module, importedFunctions, functions) + if err != nil { + return nil, err } // After engine creation, we can create the funcref element instances and initialize funcref type globals. @@ -384,6 +409,8 @@ func (s *Store) instantiate( return nil, err } + m.applyTableInits(tables, tableInit) + // Compile the default context for calls to this module. callCtx := NewCallContext(ns, m, sysCtx) m.CallCtx = callCtx diff --git a/internal/wasm/store_test.go b/internal/wasm/store_test.go index 09e3c8ad..e2eee87a 100644 --- a/internal/wasm/store_test.go +++ b/internal/wasm/store_test.go @@ -257,7 +257,7 @@ func TestStore_Instantiate_Errors(t *testing.T) { require.EqualError(t, err, "module[non-exist] not instantiated") }) - t.Run("compilation failed", func(t *testing.T) { + t.Run("creating engine failed", func(t *testing.T) { s, ns := newStore() _, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil) @@ -283,7 +283,7 @@ func TestStore_Instantiate_Errors(t *testing.T) { importingModule.BuildFunctionDefinitions() _, err = s.Instantiate(testCtx, ns, importingModule, importingModuleName, nil) - require.EqualError(t, err, "compilation failed: some compilation error") + require.EqualError(t, err, "some engine creation error") }) t.Run("start func failed", func(t *testing.T) { @@ -379,13 +379,19 @@ func (e *mockEngine) CompiledModuleCount() uint32 { return 0 } func (e *mockEngine) DeleteCompiledModule(*Module) {} // NewModuleEngine implements the same method as documented on wasm.Engine. -func (e *mockEngine) NewModuleEngine(_ string, _ *Module, _, _ []*FunctionInstance, _ []*TableInstance, _ []TableInitEntry) (ModuleEngine, error) { +func (e *mockEngine) NewModuleEngine(_ string, _ *Module, _, _ []*FunctionInstance) (ModuleEngine, error) { if e.shouldCompileFail { - return nil, fmt.Errorf("some compilation error") + return nil, fmt.Errorf("some engine creation error") } return &mockModuleEngine{callFailIndex: e.callFailIndex}, nil } +// FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine. +func (e *mockModuleEngine) FunctionInstanceReference(Index) Reference { + return 0 +} + +// NewCallEngine implements the same method as documented on wasm.ModuleEngine. func (e *mockModuleEngine) NewCallEngine(callCtx *CallContext, f *FunctionInstance) (CallEngine, error) { return &mockCallEngine{f: f, callFailIndex: e.callFailIndex}, nil } diff --git a/internal/wasm/table.go b/internal/wasm/table.go index 1a64ae65..587f7ab8 100644 --- a/internal/wasm/table.go +++ b/internal/wasm/table.go @@ -245,7 +245,7 @@ func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []*Table // If the result `init` is non-nil, it is the `tableInit` parameter of Engine.NewModuleEngine. // // Note: An error is only possible when an ElementSegment.OffsetExpr is out of range of the TableInstance.Min. -func (m *Module) buildTables(importedTables []*TableInstance, importedGlobals []*GlobalInstance, skipBoundCheck bool) (tables []*TableInstance, inits []TableInitEntry, err error) { +func (m *Module) buildTables(importedTables []*TableInstance, importedGlobals []*GlobalInstance, skipBoundCheck bool) (tables []*TableInstance, inits []tableInitEntry, err error) { tables = importedTables for _, tsec := range m.TableSection { @@ -279,22 +279,33 @@ func (m *Module) buildTables(importedTables []*TableInstance, importedGlobals [] } } - if table := tables[elem.tableIndex]; table.Type == RefTypeExternref { - // ExternRef elements are guaranteed to be all null via the validation phase, - // so applies null references. - for i := range elem.init { - table.References[offset+uint32(i)] = uintptr(0) - } + if table.Type == RefTypeExternref { + inits = append(inits, tableInitEntry{ + tableIndex: elem.tableIndex, offset: offset, + // ExternRef elements are guaranteed to be all null via the validation phase. + nullExternRefCount: len(elem.init), + }) } else { - // Only FuncRef table needs to be initialized by engines. - inits = append(inits, TableInitEntry{ - TableIndex: elem.tableIndex, Offset: offset, FunctionIndexes: elem.init, + inits = append(inits, tableInitEntry{ + tableIndex: elem.tableIndex, offset: offset, functionIndexes: elem.init, }) } } return } +// tableInitEntry is normalized element segment used for initializing tables. +type tableInitEntry struct { + tableIndex Index + // offset is the offset in the table from which the table is initialized by engine. + offset Index + // functionIndexes contains nullable function indexes. This is set when the target table has RefTypeFuncref. + functionIndexes []*Index + // nullExternRefCount is the number of nul reference which is the only available RefTypeExternref value in elements as of + // WebAssembly 2.0. This is set when the target table has RefTypeExternref. + nullExternRefCount int +} + // checkSegmentBounds fails if the capacity needed for an ElementSegment.Init is larger than limitsType.Min // // WebAssembly 1.0 (20191205) doesn't forbid growing to accommodate element segments, and spectests are inconsistent. diff --git a/internal/wasm/table_test.go b/internal/wasm/table_test.go index 2b401af8..72409522 100644 --- a/internal/wasm/table_test.go +++ b/internal/wasm/table_test.go @@ -678,7 +678,7 @@ func TestModule_buildTables(t *testing.T) { importedTables []*TableInstance importedGlobals []*GlobalInstance expectedTables []*TableInstance - expectedInit []TableInitEntry + expectedInit []tableInitEntry }{ { name: "empty", @@ -713,6 +713,17 @@ func TestModule_buildTables(t *testing.T) { }, expectedTables: []*TableInstance{{References: make([]Reference, 1), Min: 1}}, }, + { + name: "null extern refs", + module: &Module{ + TableSection: []*Table{{Min: 10, Type: RefTypeExternref}}, + validatedActiveElementSegments: []*validatedActiveElementSegment{ + {opcode: OpcodeI32Const, arg: 5, init: []*Index{nil, nil, nil}}, // three null refs. + }, + }, + expectedTables: []*TableInstance{{References: make([]Reference, 10), Min: 10, Type: RefTypeExternref}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 5, nullExternRefCount: 3}}, + }, { name: "constant derived element offset=0 and one index", module: &Module{ @@ -725,7 +736,7 @@ func TestModule_buildTables(t *testing.T) { }, }, expectedTables: []*TableInstance{{References: make([]Reference, 1), Min: 1}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 0, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 0, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "constant derived element offset - imported table", @@ -739,7 +750,7 @@ func TestModule_buildTables(t *testing.T) { }, importedTables: []*TableInstance{{Min: 2}}, expectedTables: []*TableInstance{{Min: 2}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 0, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 0, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "constant derived element offset=0 and one index - imported table", @@ -754,7 +765,7 @@ func TestModule_buildTables(t *testing.T) { }, importedTables: []*TableInstance{{Min: 1}}, expectedTables: []*TableInstance{{Min: 1}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 0, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 0, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "constant derived element offset and two indices", @@ -768,7 +779,7 @@ func TestModule_buildTables(t *testing.T) { }, }, expectedTables: []*TableInstance{{References: make([]Reference, 3), Min: 3}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}}, }, { // See: https://github.com/WebAssembly/spec/issues/1427 name: "imported global derived element offset and no index", @@ -801,7 +812,7 @@ func TestModule_buildTables(t *testing.T) { }, importedGlobals: []*GlobalInstance{{Type: &GlobalType{ValType: ValueTypeI32}, Val: 1}}, expectedTables: []*TableInstance{{References: make([]Reference, 2), Min: 2}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "imported global derived element offset and one index - imported table", @@ -820,7 +831,7 @@ func TestModule_buildTables(t *testing.T) { importedGlobals: []*GlobalInstance{{Type: &GlobalType{ValType: ValueTypeI32}, Val: 1}}, importedTables: []*TableInstance{{References: make([]Reference, 2), Min: 2}}, expectedTables: []*TableInstance{{Min: 2, References: []Reference{0, 0}}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "imported global derived element offset - ignores min on imported table", @@ -839,7 +850,7 @@ func TestModule_buildTables(t *testing.T) { importedGlobals: []*GlobalInstance{{Type: &GlobalType{ValType: ValueTypeI32}, Val: 1}}, importedTables: []*TableInstance{{References: make([]Reference, 2), Min: 2}}, expectedTables: []*TableInstance{{Min: 2, References: []Reference{0, 0}}}, - expectedInit: []TableInitEntry{{TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0)}}}, + expectedInit: []tableInitEntry{{tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0)}}}, }, { name: "imported global derived element offset - two indices", @@ -877,9 +888,9 @@ func TestModule_buildTables(t *testing.T) { {References: make([]Reference, 3), Min: 3}, {References: make([]Reference, 100), Min: 100}, }, - expectedInit: []TableInitEntry{ - {TableIndex: 1, Offset: 3, FunctionIndexes: []*Index{nil, uint32Ptr(2)}}, - {TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}, + expectedInit: []tableInitEntry{ + {tableIndex: 1, offset: 3, functionIndexes: []*Index{nil, uint32Ptr(2)}}, + {tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}, }, }, { @@ -903,9 +914,9 @@ func TestModule_buildTables(t *testing.T) { {Type: &GlobalType{ValType: ValueTypeI32}, Val: 1}, }, expectedTables: []*TableInstance{{References: make([]Reference, 3), Min: 3}}, - expectedInit: []TableInitEntry{ - {TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}, - {TableIndex: 0, Offset: 1, FunctionIndexes: []*Index{uint32Ptr(1), uint32Ptr(2)}}, + expectedInit: []tableInitEntry{ + {tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(0), uint32Ptr(2)}}, + {tableIndex: 0, offset: 1, functionIndexes: []*Index{uint32Ptr(1), uint32Ptr(2)}}, }, }, } diff --git a/runtime_test.go b/runtime_test.go index 720effdc..76a401bd 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -664,6 +664,6 @@ func (e *mockEngine) DeleteCompiledModule(module *wasm.Module) { } // NewModuleEngine implements the same method as documented on wasm.Engine. -func (e *mockEngine) NewModuleEngine(_ string, _ *wasm.Module, _, _ []*wasm.FunctionInstance, _ []*wasm.TableInstance, _ []wasm.TableInitEntry) (wasm.ModuleEngine, error) { +func (e *mockEngine) NewModuleEngine(_ string, _ *wasm.Module, _, _ []*wasm.FunctionInstance) (wasm.ModuleEngine, error) { return nil, nil }