Import function type check at validation phrase (#1281)
Import function type check at compilation Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -455,6 +455,10 @@ func (m *Module) validateImports(enabledFeatures api.CoreFeatures) error {
|
||||
return fmt.Errorf("import[%d] has an empty module name", i)
|
||||
}
|
||||
switch imp.Type {
|
||||
case ExternTypeFunc:
|
||||
if int(imp.DescFunc) >= len(m.TypeSection) {
|
||||
return fmt.Errorf("invalid import[%q.%q] function: type index out of range", imp.Module, imp.Name)
|
||||
}
|
||||
case ExternTypeGlobal:
|
||||
if !imp.DescGlobal.Mutable {
|
||||
continue
|
||||
|
||||
@@ -585,6 +585,12 @@ func TestModule_validateImports(t *testing.T) {
|
||||
enabledFeatures: api.CoreFeaturesV1,
|
||||
i: &Import{Module: "m", Name: "n", Type: ExternTypeFunc, DescFunc: 0},
|
||||
},
|
||||
{
|
||||
name: "func type index out of range ",
|
||||
enabledFeatures: api.CoreFeaturesV1,
|
||||
i: &Import{Module: "m", Name: "n", Type: ExternTypeFunc, DescFunc: 100},
|
||||
expectedErr: "invalid import[\"m\".\"n\"] function: type index out of range",
|
||||
},
|
||||
{
|
||||
name: "global var disabled",
|
||||
enabledFeatures: api.CoreFeaturesV1.SetEnabled(api.CoreFeatureMutableGlobal, false),
|
||||
@@ -621,7 +627,7 @@ func TestModule_validateImports(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
m := Module{}
|
||||
m := Module{TypeSection: []FunctionType{{}}}
|
||||
if tc.i != nil {
|
||||
m.ImportSection = []Import{*tc.i}
|
||||
}
|
||||
|
||||
@@ -407,19 +407,12 @@ func (m *ModuleInstance) resolveImports(module *Module, importedModules map[stri
|
||||
|
||||
switch i.Type {
|
||||
case ExternTypeFunc:
|
||||
typeIndex := i.DescFunc
|
||||
// TODO: this shouldn't be possible as invalid should fail validate
|
||||
if int(typeIndex) >= len(module.TypeSection) {
|
||||
err = errorInvalidImport(i, idx, fmt.Errorf("function type out of range"))
|
||||
return
|
||||
}
|
||||
expectedType := &module.TypeSection[i.DescFunc]
|
||||
importedFunction := &importedModule.Functions[imported.Index]
|
||||
|
||||
d := importedFunction.Definition
|
||||
if !expectedType.EqualsSignature(d.ParamTypes(), d.ResultTypes()) {
|
||||
actualType := &FunctionType{Params: d.ParamTypes(), Results: d.ResultTypes()}
|
||||
err = errorInvalidImport(i, idx, fmt.Errorf("signature mismatch: %s != %s", expectedType, actualType))
|
||||
expectedTypeID := m.TypeIDs[i.DescFunc]
|
||||
importedTypeID := importedFunction.TypeID
|
||||
if importedTypeID != expectedTypeID {
|
||||
err = errorInvalidImport(i, idx, fmt.Errorf("signature mismatch: %s != %s",
|
||||
&module.TypeSection[i.DescFunc], importedFunction.Type))
|
||||
return
|
||||
}
|
||||
m.Functions[fs] = *importedFunction
|
||||
@@ -430,6 +423,7 @@ func (m *ModuleInstance) resolveImports(module *Module, importedModules map[stri
|
||||
if expected.Type != importedTable.Type {
|
||||
err = errorInvalidImport(i, idx, fmt.Errorf("table type mismatch: %s != %s",
|
||||
RefTypeName(expected.Type), RefTypeName(importedTable.Type)))
|
||||
return
|
||||
}
|
||||
|
||||
if expected.Min > importedTable.Min {
|
||||
|
||||
@@ -658,11 +658,12 @@ func Test_resolveImports(t *testing.T) {
|
||||
require.EqualError(t, err, "\"unknown\" is not exported in module \"test\"")
|
||||
})
|
||||
t.Run("func", func(t *testing.T) {
|
||||
typeIDs := []FunctionTypeID{100, 200}
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
externMod := &ModuleInstance{
|
||||
Functions: []FunctionInstance{
|
||||
{Definition: &FunctionDefinition{funcType: &FunctionType{Results: []ValueType{ValueTypeF32}}}},
|
||||
{Definition: &FunctionDefinition{funcType: &FunctionType{Results: []ValueType{ValueTypeI32}}}},
|
||||
{TypeID: typeIDs[0], Definition: &FunctionDefinition{funcType: &FunctionType{Results: []ValueType{ValueTypeF32}}}},
|
||||
{TypeID: typeIDs[1], Definition: &FunctionDefinition{funcType: &FunctionType{Results: []ValueType{ValueTypeI32}}}},
|
||||
},
|
||||
Exports: map[string]*Export{
|
||||
name: {Type: ExternTypeFunc, Index: 0},
|
||||
@@ -681,24 +682,16 @@ func Test_resolveImports(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
m := &ModuleInstance{Functions: make([]FunctionInstance, 2)}
|
||||
m := &ModuleInstance{Functions: make([]FunctionInstance, 2), TypeIDs: typeIDs}
|
||||
err := m.resolveImports(module, importedModules)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, m.Functions[0], externMod.Functions[0])
|
||||
require.Equal(t, m.Functions[1], externMod.Functions[1])
|
||||
})
|
||||
t.Run("type out of range", func(t *testing.T) {
|
||||
modules := map[string]*ModuleInstance{
|
||||
moduleName: {Exports: map[string]*Export{name: {}}, Name: moduleName},
|
||||
}
|
||||
m := &ModuleInstance{Functions: make([]FunctionInstance, 1)}
|
||||
err := m.resolveImports(&Module{ImportSection: []Import{{Module: moduleName, Name: name, Type: ExternTypeFunc, DescFunc: 100}}}, modules)
|
||||
require.EqualError(t, err, "import[0] func[test.target]: function type out of range")
|
||||
})
|
||||
t.Run("signature mismatch", func(t *testing.T) {
|
||||
externMod := &ModuleInstance{
|
||||
Functions: []FunctionInstance{{Definition: &FunctionDefinition{funcType: &FunctionType{}}}},
|
||||
Functions: []FunctionInstance{{TypeID: 123435, Type: &FunctionType{}}},
|
||||
Exports: map[string]*Export{
|
||||
name: {Type: ExternTypeFunc, Index: 0},
|
||||
},
|
||||
@@ -709,7 +702,7 @@ func Test_resolveImports(t *testing.T) {
|
||||
ImportSection: []Import{{Module: moduleName, Name: name, Type: ExternTypeFunc, DescFunc: 0}},
|
||||
}
|
||||
|
||||
m := &ModuleInstance{Functions: make([]FunctionInstance, 1)}
|
||||
m := &ModuleInstance{Functions: make([]FunctionInstance, 1), TypeIDs: typeIDs}
|
||||
err := m.resolveImports(module, map[string]*ModuleInstance{moduleName: externMod})
|
||||
require.EqualError(t, err, "import[0] func[test.target]: signature mismatch: v_f32 != v_v")
|
||||
})
|
||||
|
||||
@@ -61,6 +61,20 @@ func Test_resolveImports_table(t *testing.T) {
|
||||
err := m.resolveImports(&Module{ImportSection: []Import{{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: importTableType}}}, importedModules)
|
||||
require.EqualError(t, err, "import[0] table[test.target]: maximum size mismatch: 10, but actual has no max")
|
||||
})
|
||||
t.Run("type mismatch", func(t *testing.T) {
|
||||
importedModules := map[string]*ModuleInstance{
|
||||
moduleName: {
|
||||
Tables: []*TableInstance{{Type: RefTypeFuncref}},
|
||||
Exports: map[string]*Export{name: {Type: ExternTypeTable}},
|
||||
Name: moduleName,
|
||||
},
|
||||
}
|
||||
m := &ModuleInstance{Tables: make([]*TableInstance, 1)}
|
||||
err := m.resolveImports(&Module{ImportSection: []Import{
|
||||
{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: Table{Type: RefTypeExternref}},
|
||||
}}, importedModules)
|
||||
require.EqualError(t, err, "import[0] table[test.target]: table type mismatch: externref != funcref")
|
||||
})
|
||||
}
|
||||
|
||||
var codeEnd = Code{Body: []byte{OpcodeEnd}}
|
||||
|
||||
Reference in New Issue
Block a user