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:
Takeshi Yoneda
2023-03-24 01:10:18 -07:00
committed by GitHub
parent 244c5c5792
commit d0fc0c6232
5 changed files with 37 additions and 26 deletions

View File

@@ -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

View File

@@ -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}
}

View File

@@ -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 {

View File

@@ -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")
})

View File

@@ -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}}