diff --git a/internal/engine/compiler/impl_vec_amd64.go b/internal/engine/compiler/impl_vec_amd64.go index 874463b7..f030316c 100644 --- a/internal/engine/compiler/impl_vec_amd64.go +++ b/internal/engine/compiler/impl_vec_amd64.go @@ -308,7 +308,7 @@ func (c *amd64Compiler) compileV128ExtractLane(o *wazeroir.OperationV128ExtractL } c.assembler.CompileRegisterToRegisterWithArg(amd64.PEXTRB, val.register, result, o.LaneIndex) if o.Signed { - c.assembler.CompileRegisterToRegister(amd64.MOVBQSX, result, result) + c.assembler.CompileRegisterToRegister(amd64.MOVBLSX, result, result) } else { c.assembler.CompileRegisterToRegister(amd64.MOVBLZX, result, result) } diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go index b3b23f6f..8d447602 100644 --- a/internal/engine/interpreter/interpreter.go +++ b/internal/engine/interpreter/interpreter.go @@ -2279,7 +2279,7 @@ func (ce *callEngine) callNativeFunc(ctx context.Context, callCtx *wasm.CallCont } if op.b3 { // sign-extend. - v = uint64(int8(u8)) + v = uint64(uint32(int8(u8))) } else { v = uint64(u8) } @@ -2292,7 +2292,7 @@ func (ce *callEngine) callNativeFunc(ctx context.Context, callCtx *wasm.CallCont } if op.b3 { // sign-extend. - v = uint64(int16(u16)) + v = uint64(uint32(int16(u16))) } else { v = uint64(u16) } diff --git a/internal/integration_test/README.md b/internal/integration_test/README.md index 91330896..b5ba72d5 100644 --- a/internal/integration_test/README.md +++ b/internal/integration_test/README.md @@ -2,6 +2,7 @@ This directory contains tests which use multiple packages. For example: * `bench` contains benchmark tests. * `engine` contains variety of end-to-end tests, mainly to ensure the consistency in the behavior between engines. +* `fuzzcases` contains variety of test cases found by [wazero-fuzz](https://github.com/tetratelabs/wazero-fuzz). * `post1_0` contains end-to-end tests for features [finished](https://github.com/WebAssembly/proposals/blob/main/finished-proposals.md) after WebAssembly 1.0 (20191205). * `spectest` contains end-to-end tests with the [WebAssembly specification tests](https://github.com/WebAssembly/spec/tree/wg-1.0/test/core). * `vs` tests and benchmarks VS other WebAssembly runtimes. diff --git a/internal/integration_test/fuzzcases/README.md b/internal/integration_test/fuzzcases/README.md new file mode 100644 index 00000000..9accd8c9 --- /dev/null +++ b/internal/integration_test/fuzzcases/README.md @@ -0,0 +1,2 @@ +Here we collect the test cases found by [wazero-fuzz](https://github.com/tetratelabs/wazero-fuzz). +The test data in `./testdata` directory is named as `12345.wat` where the numebr corresponds to the PR or issue in this repostiroy. diff --git a/internal/integration_test/fuzzcases/fuzzcases_test.go b/internal/integration_test/fuzzcases/fuzzcases_test.go new file mode 100644 index 00000000..87c95015 --- /dev/null +++ b/internal/integration_test/fuzzcases/fuzzcases_test.go @@ -0,0 +1,54 @@ +package fuzzcases + +import ( + "context" + _ "embed" + "testing" + + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/internal/platform" + "github.com/tetratelabs/wazero/internal/testing/require" +) + +var ctx = context.Background() + +var ( + //go:embed testdata/695.wasm + case695 []byte +) + +func newRuntimeCompiler() wazero.Runtime { + return wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigCompiler().WithWasmCore2()) +} + +func newRuntimeInterpreter() wazero.Runtime { + return wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter().WithWasmCore2()) +} + +// 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 + } + + 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.Contains(t, err.Error(), "out of bounds memory access") + + _, err = module.ExportedFunction("i16x8s").Call(ctx) + require.Contains(t, err.Error(), "out of bounds memory access") + }) + } +} diff --git a/internal/integration_test/fuzzcases/testdata/695.wasm b/internal/integration_test/fuzzcases/testdata/695.wasm new file mode 100644 index 00000000..1f41f510 Binary files /dev/null and b/internal/integration_test/fuzzcases/testdata/695.wasm differ diff --git a/internal/integration_test/fuzzcases/testdata/695.wat b/internal/integration_test/fuzzcases/testdata/695.wat new file mode 100644 index 00000000..9b1f3d34 --- /dev/null +++ b/internal/integration_test/fuzzcases/testdata/695.wat @@ -0,0 +1,16 @@ +(module + (type (func)) + (func (export "i8x16s") (type 0) + v128.const i8x16 0x0 0xff 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + i8x16.extract_lane_s 1 ;; uint32(int8(0xff)) = 0xffff_ffff + ;; if the signed extend is 64-bit, then the offset 0xffff_ffff_ffff_ffff + 1= 0 and not result in out of bounds. + v128.load32_zero offset=1 align=1 + unreachable) + (func (export "i16x8s") (type 0) + v128.const i16x8 0x0 0xffff 0x0 0x0 0x0 0x0 0x0 0x0 + i16x8.extract_lane_s 1 ;; uint32(int16(0xffff)) = 0xffff_ffff + ;; if the signed extend is 64-bit, then the offset 0xffff_ffff_ffff_ffff + 1= 0 and not result in out of bounds. + v128.load32_zero offset=1 align=1 + unreachable) + (memory 1 1) +)