package fuzzcases import ( "context" "embed" "fmt" "testing" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/internal/testing/binaryencoding" "github.com/tetratelabs/wazero/internal/testing/require" "github.com/tetratelabs/wazero/internal/wasm" ) var ctx = context.Background() //go:embed testdata/*.wasm var testcases embed.FS func getWasmBinary(t *testing.T, number int) []byte { ret, err := testcases.ReadFile(fmt.Sprintf("testdata/%d.wasm", number)) require.NoError(t, err) return ret } 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(ctx, wazero.NewRuntimeConfigCompiler()) defer r.Close(ctx) runner(t, r) }) } func runWithInterpreter(t *testing.T, runner func(t *testing.T, r wazero.Runtime)) { t.Run("interpreter", func(t *testing.T) { r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter()) 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) { run(t, func(t *testing.T, r wazero.Runtime) { module, err := r.Instantiate(ctx, getWasmBinary(t, 695)) 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("i16x8s").Call(ctx) require.NotNil(t, err) require.Contains(t, err.Error(), "out of bounds memory access") }) } func Test696(t *testing.T) { functionNames := [4]string{ "select with 0 / after calling dummy", "select with 0", "typed select with 1 / after calling dummy", "typed select with 1", } run(t, func(t *testing.T, r wazero.Runtime) { module, err := r.Instantiate(ctx, getWasmBinary(t, 696)) 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) { run(t, func(t *testing.T, r wazero.Runtime) { defer r.Close(ctx) _, err := r.Instantiate(ctx, getWasmBinary(t, 699)) 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) { run(t, func(t *testing.T, r wazero.Runtime) { module, err := r.Instantiate(ctx, getWasmBinary(t, 701)) 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.extend8_s").Call(ctx) require.NotNil(t, err) require.Contains(t, err.Error(), "out of bounds memory access") }) } func Test704(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { _, err := r.Instantiate(ctx, getWasmBinary(t, 704)) require.NoError(t, err) }) } func Test708(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { _, err := r.Instantiate(ctx, getWasmBinary(t, 708)) require.NotNil(t, err) require.Contains(t, err.Error(), "out of bounds memory access") }) } func Test709(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 709)) 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]) }) } func Test715(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 715)) 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]) }) } func Test716(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 716)) require.NoError(t, err) f := mod.ExportedFunction("select on ref.func") require.NotNil(t, f) res, err := f.Call(ctx) require.NoError(t, err) require.Equal(t, uint64(1), res[0]) }) } func Test717(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 717)) require.NoError(t, err) f := mod.ExportedFunction("vectors") require.NotNil(t, f) res, err := f.Call(ctx) require.NoError(t, err) const expectedLen = 35 require.Equal(t, expectedLen, len(res)) for i := 0; i < expectedLen; i++ { require.Equal(t, uint64(i), res[i]) } }) } func Test718(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 718)) require.NoError(t, err) f := mod.ExportedFunction("v128.load_zero on the ceil") require.NotNil(t, f) _, err = f.Call(ctx) require.NoError(t, err) }) } func Test719(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 719)) require.NoError(t, err) f := mod.ExportedFunction("require unreachable") require.NotNil(t, f) _, err = f.Call(ctx) require.Error(t, err) require.Contains(t, err.Error(), "wasm error: unreachable\nwasm stack trace:") }) } func Test720(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 720)) require.NoError(t, err) f := mod.ExportedFunction("access memory after table.grow") require.NotNil(t, f) res, err := f.Call(ctx) require.NoError(t, err) require.Equal(t, uint32(0xffffffff), uint32(res[0])) }) } func Test721(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 721)) require.NoError(t, err) f := mod.ExportedFunction("conditional before elem.drop") require.NotNil(t, f) ret, err := f.Call(ctx) require.NoError(t, err) require.Equal(t, uint64(1), ret[0]) }) } func Test722(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 722)) require.NoError(t, err) f := mod.ExportedFunction("conditional before data.drop") require.NotNil(t, f) ret, err := f.Call(ctx) require.NoError(t, err) require.Equal(t, uint64(1), ret[0]) }) } func Test725(t *testing.T) { functions := []string{"i32.load8_s", "i32.load16_s"} run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 725)) require.NoError(t, err) for _, fn := range functions { f := mod.ExportedFunction(fn) require.NotNil(t, f) _, err := f.Call(ctx) require.Error(t, err) require.Contains(t, err.Error(), "out of bounds memory") } }) } // Test730 ensures that the vector min/max operations comply with the spec wrt sign bits of zeros: // // - min(0, 0) = 0, min(-0, 0) = -0, min(0, -0) = -0, min(-0, -0) = -0 // - max(0, 0) = 0, max(-0, 0) = 0, max(0, -0) = 0, max(-0, -0) = -0 func Test730(t *testing.T) { tests := []struct { name string exp [2]uint64 }{ {name: "f32x4.max", exp: [2]uint64{0x80000000 << 32, 0x00000000}}, {name: "f32x4.min", exp: [2]uint64{0x80000000, 0x80000000<<32 | 0x80000000}}, {name: "f64x2.max", exp: [2]uint64{0, 0}}, {name: "f64x2.min", exp: [2]uint64{1 << 63, 1 << 63}}, {name: "f64x2.max/mix", exp: [2]uint64{0, 1 << 63}}, {name: "f64x2.min/mix", exp: [2]uint64{1 << 63, 0}}, } run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 730)) require.NoError(t, err) for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { f := mod.ExportedFunction(tc.name) require.NotNil(t, f) actual, err := f.Call(ctx) require.NoError(t, err) require.Equal(t, tc.exp[:], actual) }) } }) } func Test733(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 733)) require.NoError(t, err) name := "out of bounds" t.Run(name, func(t *testing.T) { f := mod.ExportedFunction(name) require.NotNil(t, f) _, err = f.Call(ctx) require.Error(t, err) require.Contains(t, err.Error(), "out of bounds memory") }) name = "store higher offset" t.Run(name, func(t *testing.T) { if testing.Short() { // Note: this case uses large memory space, so can be slow like 1 to 2 seconds even without -race. t.SkipNow() } f := mod.ExportedFunction(name) require.NotNil(t, f) _, err = f.Call(ctx) require.NoError(t, err) mem := mod.Memory() require.NotNil(t, mem) v, ok := mem.ReadUint64Le(0x80000100) require.True(t, ok) require.Equal(t, uint64(0xffffffffffffffff), v) }) }) } func Test873(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { _, err := r.Instantiate(ctx, getWasmBinary(t, 873)) require.NoError(t, err) }) } func Test874(t *testing.T) { run(t, func(t *testing.T, r wazero.Runtime) { _, err := r.Instantiate(ctx, getWasmBinary(t, 874)) require.NoError(t, err) }) } func Test888(t *testing.T) { // This tests that importing FuncRef type globals and using it as an initialization of the locally-defined // FuncRef global works fine. run(t, func(t *testing.T, r wazero.Runtime) { imported := binaryencoding.EncodeModule(&wasm.Module{ MemorySection: &wasm.Memory{Min: 0, Max: 5, IsMaxEncoded: true}, GlobalSection: []wasm.Global{ { Type: wasm.GlobalType{ ValType: wasm.ValueTypeFuncref, Mutable: false, }, Init: wasm.ConstantExpression{ Opcode: wasm.OpcodeRefNull, Data: []byte{wasm.ValueTypeFuncref}, }, }, }, ExportSection: []wasm.Export{ {Name: "", Type: wasm.ExternTypeGlobal, Index: 0}, {Name: "s", Type: wasm.ExternTypeMemory, Index: 0}, }, }) _, err := r.InstantiateWithConfig(ctx, imported, wazero.NewModuleConfig().WithName("host")) require.NoError(t, err) _, err = r.InstantiateWithConfig(ctx, getWasmBinary(t, 888), wazero.NewModuleConfig().WithName("test")) require.NoError(t, err) }) } func Test1054(t *testing.T) { if !platform.CompilerSupported() { return } modules := make([]api.Module, 0, 2) run(t, func(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(ctx, getWasmBinary(t, 1054)) require.NoError(t, err) modules = append(modules, mod) }) // Checks if the memory state is the same between engines. require.Equal(t, modules[0].Memory().(*wasm.MemoryInstance).Buffer, modules[1].Memory().(*wasm.MemoryInstance).Buffer, ) }