compiler: save conditional values at table.size (#715)

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
Takeshi Yoneda
2022-07-25 13:32:32 +09:00
committed by GitHub
parent ed068597cd
commit 8d75403c49
5 changed files with 108 additions and 153 deletions

View File

@@ -27,51 +27,51 @@ var (
case708 []byte
//go:embed testdata/709.wasm
case709 []byte
//go:embed testdata/715.wasm
case715 []byte
)
func newRuntimeCompiler() wazero.Runtime {
return wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigCompiler().WithWasmCore2())
func runWithCompiler(t *testing.T, runner func(t *testing.T, r wazero.Runtime)) {
if !platform.CompilerSupported() {
return
}
t.Run("compiler", func(t *testing.T) {
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigCompiler().WithWasmCore2())
defer r.Close(ctx)
runner(t, r)
})
}
func newRuntimeInterpreter() wazero.Runtime {
return wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter().WithWasmCore2())
func runWithInterpreter(t *testing.T, runner func(t *testing.T, r wazero.Runtime)) {
t.Run("interpreter", func(t *testing.T) {
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter().WithWasmCore2())
defer r.Close(ctx)
runner(t, r)
})
}
func run(t *testing.T, runner func(t *testing.T, r wazero.Runtime)) {
runWithInterpreter(t, runner)
runWithCompiler(t, runner)
}
// Test695 requires two functions to exit with "out of bounds memory access" consistently across the implementations.
func Test695(t *testing.T) {
if !platform.CompilerSupported() {
return
}
run(t, func(t *testing.T, r wazero.Runtime) {
module, err := r.InstantiateModuleFromBinary(ctx, case695)
require.NoError(t, err)
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
module, err := tc.r.InstantiateModuleFromBinary(ctx, case695)
require.NoError(t, err)
_, err = module.ExportedFunction("i8x16s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
_, err = module.ExportedFunction("i8x16s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
_, err = module.ExportedFunction("i16x8s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
_, err = module.ExportedFunction("i16x8s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
func Test696(t *testing.T) {
if !platform.CompilerSupported() {
return
}
functionNames := [4]string{
"select with 0 / after calling dummy",
"select with 0",
@@ -79,148 +79,83 @@ func Test696(t *testing.T) {
"typed select with 1",
}
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
module, err := tc.r.InstantiateModuleFromBinary(ctx, case696)
require.NoError(t, err)
run(t, func(t *testing.T, r wazero.Runtime) {
module, err := r.InstantiateModuleFromBinary(ctx, case696)
require.NoError(t, err)
for _, name := range functionNames {
_, err := module.ExportedFunction(name).Call(ctx)
require.NoError(t, err)
}
})
}
for _, name := range functionNames {
_, err := module.ExportedFunction(name).Call(ctx)
require.NoError(t, err)
}
})
}
// Test699 ensures that accessing element instances and data instances works
// without crash even when the access happens in the nested function call.
func Test699(t *testing.T) {
if !platform.CompilerSupported() {
return
}
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
_, err := tc.r.InstantiateModuleFromBinary(ctx, case699)
require.NoError(t, err)
})
}
run(t, func(t *testing.T, r wazero.Runtime) {
defer r.Close(ctx)
_, err := r.InstantiateModuleFromBinary(ctx, case699)
require.NoError(t, err)
})
}
// Test701 requires two functions to exit with "out of bounds memory access" consistently across the implementations.
func Test701(t *testing.T) {
if !platform.CompilerSupported() {
return
}
run(t, func(t *testing.T, r wazero.Runtime) {
module, err := r.InstantiateModuleFromBinary(ctx, case701)
require.NoError(t, err)
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
module, err := tc.r.InstantiateModuleFromBinary(ctx, case701)
require.NoError(t, err)
_, err = module.ExportedFunction("i32.extend16_s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
_, err = module.ExportedFunction("i32.extend16_s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
_, err = module.ExportedFunction("i32.extend8_s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
_, err = module.ExportedFunction("i32.extend8_s").Call(ctx)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
func Test704(t *testing.T) {
if !platform.CompilerSupported() {
return
}
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
_, err := tc.r.InstantiateModuleFromBinary(ctx, case704)
require.NoError(t, err)
})
}
run(t, func(t *testing.T, r wazero.Runtime) {
_, err := r.InstantiateModuleFromBinary(ctx, case704)
require.NoError(t, err)
})
}
func Test708(t *testing.T) {
if !platform.CompilerSupported() {
return
}
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
_, err := tc.r.InstantiateModuleFromBinary(ctx, case708)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
run(t, func(t *testing.T, r wazero.Runtime) {
_, err := r.InstantiateModuleFromBinary(ctx, case708)
require.NotNil(t, err)
require.Contains(t, err.Error(), "out of bounds memory access")
})
}
func Test709(t *testing.T) {
if !platform.CompilerSupported() {
return
}
run(t, func(t *testing.T, r wazero.Runtime) {
mod, err := r.InstantiateModuleFromBinary(ctx, case709)
require.NoError(t, err)
for _, tc := range []struct {
name string
r wazero.Runtime
}{
{name: "compiler", r: newRuntimeCompiler()},
{name: "interpreter", r: newRuntimeInterpreter()},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
defer tc.r.Close(ctx)
mod, err := tc.r.InstantiateModuleFromBinary(ctx, case709)
require.NoError(t, err)
f := mod.ExportedFunction("f64x2.promote_low_f32x4")
require.NotNil(t, f)
res, err := f.Call(ctx)
require.NoError(t, err)
f := mod.ExportedFunction("f64x2.promote_low_f32x4")
require.NotNil(t, f)
res, err := f.Call(ctx)
require.NoError(t, err)
require.NotEqual(t, uint64(0), res[0])
require.NotEqual(t, uint64(0), res[1])
})
}
require.NotEqual(t, uint64(0), res[0])
require.NotEqual(t, uint64(0), res[1])
})
}
func Test715(t *testing.T) {
run(t, func(t *testing.T, r wazero.Runtime) {
mod, err := r.InstantiateModuleFromBinary(ctx, case715)
require.NoError(t, err)
f := mod.ExportedFunction("select on conditional value after table.size")
require.NotNil(t, f)
res, err := f.Call(ctx)
require.NoError(t, err)
require.Equal(t, uint64(1), res[0])
})
}

Binary file not shown.

View File

@@ -0,0 +1,13 @@
(module
(func (export "select on conditional value after table.size") (result i32)
i32.const 1234
ref.null func
ref.is_null
;; At this point, the result of ref.is_null (=1) is on the conditional register.
;; If table.size doesn't save the value into a general purpose register,
;; the result of select below becomes incorrect.
table.size 0 ;; -> 0
select ;; -> select the result of ref.is_null == 1.
)
(table 0 0 funcref)
)