compiler: save conditional values at table.size (#715)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -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])
|
||||
})
|
||||
}
|
||||
|
||||
BIN
internal/integration_test/fuzzcases/testdata/715.wasm
vendored
Normal file
BIN
internal/integration_test/fuzzcases/testdata/715.wasm
vendored
Normal file
Binary file not shown.
13
internal/integration_test/fuzzcases/testdata/715.wat
vendored
Normal file
13
internal/integration_test/fuzzcases/testdata/715.wat
vendored
Normal 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)
|
||||
)
|
||||
Reference in New Issue
Block a user