Fixes global numeric types to have max of signed encoding (#442)

This adjusts towards the exiting code which used int32/64 instead of
uint32/64. The reason is that the spec indicates intepretation as signed
numbers, which affects the maximum value.

See https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-04-06 06:35:31 +08:00
committed by GitHub
parent b1cffcc58e
commit f5598c9a8e
14 changed files with 153 additions and 62 deletions

View File

@@ -31,9 +31,13 @@ import (
type ValueType = byte
const (
// ValueTypeI32 is a 32-bit integer.
ValueTypeI32 ValueType = 0x7f
// ValueTypeI64 is a 64-bit integer.
ValueTypeI64 ValueType = 0x7e
// ValueTypeF32 is a 32-bit floating point number.
ValueTypeF32 ValueType = 0x7d
// ValueTypeF64 is a 32-bit floating point number.
ValueTypeF64 ValueType = 0x7c
)

View File

@@ -64,11 +64,11 @@ func TestEncodeDecodeF64(t *testing.T) {
} {
t.Run(fmt.Sprintf("%f", v), func(t *testing.T) {
encoded := EncodeF64(v)
binary := DecodeF64(encoded)
if math.IsNaN(binary) { // cannot use require.Equal as NaN by definition doesn't equal itself
require.True(t, math.IsNaN(binary))
val := DecodeF64(encoded)
if math.IsNaN(val) { // cannot use require.Equal as NaN by definition doesn't equal itself
require.True(t, math.IsNaN(val))
} else {
require.Equal(t, v, binary)
require.Equal(t, v, val)
}
})
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -105,8 +106,10 @@ type ModuleBuilder interface {
// builder.ExportGlobalI32("canvas_width", 1024)
//
// Note: If a global is already exported with the same name, this overwrites it.
// Note: The maximum value of v is math.MaxInt32 to match constraints of initialization in binary format.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A2
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalI32(name string, v uint32) ModuleBuilder
ExportGlobalI32(name string, v int32) ModuleBuilder
// ExportGlobalI64 exports a global constant of type api.ValueTypeI64.
//
@@ -115,8 +118,10 @@ type ModuleBuilder interface {
// builder.ExportGlobalI64("start_epoch", 1620216263544)
//
// Note: If a global is already exported with the same name, this overwrites it.
// Note: The maximum value of v is math.MaxInt64 to match constraints of initialization in binary format.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A2
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalI64(name string, v uint64) ModuleBuilder
ExportGlobalI64(name string, v int64) ModuleBuilder
// ExportGlobalF32 exports a global constant of type api.ValueTypeF32.
//
@@ -194,19 +199,21 @@ func (b *moduleBuilder) ExportMemoryWithMax(name string, minPages, maxPages uint
}
// ExportGlobalI32 implements ModuleBuilder.ExportGlobalI32
func (b *moduleBuilder) ExportGlobalI32(name string, v uint32) ModuleBuilder {
func (b *moduleBuilder) ExportGlobalI32(name string, v int32) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(v)},
// Signed per https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(uint32(v))},
}
return b
}
// ExportGlobalI64 implements ModuleBuilder.ExportGlobalI64
func (b *moduleBuilder) ExportGlobalI64(name string, v uint64) ModuleBuilder {
func (b *moduleBuilder) ExportGlobalI64(name string, v int64) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(v)},
// Signed per https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(uint64(v))},
}
return b
}
@@ -215,7 +222,7 @@ func (b *moduleBuilder) ExportGlobalI64(name string, v uint64) ModuleBuilder {
func (b *moduleBuilder) ExportGlobalF32(name string, v float32) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(v))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(v))},
}
return b
}
@@ -224,7 +231,7 @@ func (b *moduleBuilder) ExportGlobalF32(name string, v float32) ModuleBuilder {
func (b *moduleBuilder) ExportGlobalF64(name string, v float64) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(v))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(v))},
}
return b
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -221,13 +222,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
{
name: "ExportGlobalI32 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024).ExportGlobalI32("canvas_width", 2048)
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024).ExportGlobalI32("canvas_width", math.MaxInt32)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(2048)},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(math.MaxInt32)},
},
},
ExportSection: map[string]*wasm.Export{
@@ -255,13 +256,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
{
name: "ExportGlobalI64 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544).ExportGlobalI64("start_epoch", 1620216263544000)
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544).ExportGlobalI64("start_epoch", math.MaxInt64)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(1620216263544000)},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(math.MaxInt64)},
},
},
ExportSection: map[string]*wasm.Export{
@@ -278,7 +279,7 @@ func TestNewModuleBuilder_Build(t *testing.T) {
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(3.1415926536))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(3.1415926536))},
},
},
ExportSection: map[string]*wasm.Export{
@@ -289,13 +290,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
{
name: "ExportGlobalF32 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536).ExportGlobalF32("math/pi", 3.14159)
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536).ExportGlobalF32("math/pi", math.MaxFloat32)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(3.14159))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(math.MaxFloat32))},
},
},
ExportSection: map[string]*wasm.Export{
@@ -312,7 +313,7 @@ func TestNewModuleBuilder_Build(t *testing.T) {
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(math.Pi))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.Pi))},
},
},
ExportSection: map[string]*wasm.Export{
@@ -323,13 +324,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
{
name: "ExportGlobalF64 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi).ExportGlobalF64("math/pi", 3.14159)
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi).ExportGlobalF64("math/pi", math.MaxFloat64)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(3.14159))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.MaxFloat64))},
},
},
ExportSection: map[string]*wasm.Export{

View File

@@ -6,6 +6,8 @@ import (
"math"
)
// DecodeFloat32 decodes a float32 in IEEE 754 binary representation.
// See https://www.w3.org/TR/wasm-core-1/#floating-point%E2%91%A2
func DecodeFloat32(r io.Reader) (float32, error) {
buf := make([]byte, 4)
_, err := io.ReadFull(r, buf)
@@ -16,6 +18,8 @@ func DecodeFloat32(r io.Reader) (float32, error) {
return math.Float32frombits(raw), nil
}
// DecodeFloat64 decodes a float64 in IEEE 754 binary representation.
// See https://www.w3.org/TR/wasm-core-1/#floating-point%E2%91%A2
func DecodeFloat64(r io.Reader) (float64, error) {
buf := make([]byte, 8)
_, err := io.ReadFull(r, buf)

View File

@@ -58,6 +58,7 @@ func TestDecodeUint32(t *testing.T) {
{bytes: []byte{0x80, 0x7f}, exp: 16256},
{bytes: []byte{0xe5, 0x8e, 0x26}, exp: 624485},
{bytes: []byte{0x80, 0x80, 0x80, 0x4f}, exp: 165675008},
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xf}, exp: math.MaxUint32},
{bytes: []byte{0x83, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
{bytes: []byte{0x82, 0x80, 0x80, 0x80, 0x70}, expErr: true},
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
@@ -83,6 +84,8 @@ func TestDecodeUint64(t *testing.T) {
{bytes: []byte{0x80, 0x7f}, exp: 16256},
{bytes: []byte{0xe5, 0x8e, 0x26}, exp: 624485},
{bytes: []byte{0x80, 0x80, 0x80, 0x4f}, exp: 165675008},
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xf}, exp: math.MaxUint32},
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1}, exp: math.MaxUint64},
{bytes: []byte{0x89, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x71}, expErr: true},
} {
actual, num, err := DecodeUint64(bytes.NewReader(c.bytes))

15
internal/u64/u64.go Normal file
View File

@@ -0,0 +1,15 @@
package u64
// LeBytes returns a byte array corresponding to the 8 bytes in the uint64 in little-endian byte order.
func LeBytes(v uint64) []byte {
return []byte{
byte(v),
byte(v >> 8),
byte(v >> 16),
byte(v >> 24),
byte(v >> 32),
byte(v >> 40),
byte(v >> 48),
byte(v >> 56),
}
}

39
internal/u64/u64_test.go Normal file
View File

@@ -0,0 +1,39 @@
package u64
import (
"encoding/binary"
"math"
"testing"
"github.com/stretchr/testify/require"
)
func TestBytes(t *testing.T) {
tests := []struct {
name string
input uint64
}{
{
name: "zero",
input: 0,
},
{
name: "half",
input: math.MaxUint32,
},
{
name: "max",
input: math.MaxUint64,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
expected := make([]byte, 8)
binary.LittleEndian.PutUint64(expected, tc.input)
require.Equal(t, expected, LeBytes(tc.input))
})
}
}

View File

@@ -2,12 +2,13 @@ package wasm
import (
"context"
gobinary "encoding/binary"
"math"
"testing"
"github.com/stretchr/testify/require"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/u64"
)
func TestGlobalTypes(t *testing.T) {
@@ -26,6 +27,13 @@ func TestGlobalTypes(t *testing.T) {
expectedVal: 1,
expectedString: "global(1)",
},
{
name: "i32 - immutable - max",
global: globalI32(math.MaxInt32),
expectedType: ValueTypeI32,
expectedVal: math.MaxInt32,
expectedString: "global(2147483647)",
},
{
name: "i64 - immutable",
global: globalI64(1),
@@ -33,6 +41,13 @@ func TestGlobalTypes(t *testing.T) {
expectedVal: 1,
expectedString: "global(1)",
},
{
name: "i64 - immutable - max",
global: globalI64(math.MaxInt64),
expectedType: ValueTypeI64,
expectedVal: math.MaxInt64,
expectedString: "global(9223372036854775807)",
},
{
name: "f32 - immutable",
global: globalF32(api.EncodeF32(1.0)),
@@ -40,6 +55,13 @@ func TestGlobalTypes(t *testing.T) {
expectedVal: api.EncodeF32(1.0),
expectedString: "global(1.000000)",
},
{
name: "f32 - immutable - max",
global: globalF32(api.EncodeF32(math.MaxFloat32)),
expectedType: ValueTypeF32,
expectedVal: api.EncodeF32(math.MaxFloat32),
expectedString: "global(340282346638528859811704183484516925440.000000)",
},
{
name: "f64 - immutable",
global: globalF64(api.EncodeF64(1.0)),
@@ -47,6 +69,13 @@ func TestGlobalTypes(t *testing.T) {
expectedVal: api.EncodeF64(1.0),
expectedString: "global(1.000000)",
},
{
name: "f64 - immutable - max",
global: globalF64(api.EncodeF64(math.MaxFloat64)),
expectedType: ValueTypeF64,
expectedVal: api.EncodeF64(math.MaxFloat64),
expectedString: "global(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)",
},
{
name: "i32 - mutable",
global: &mutableGlobal{g: &GlobalInstance{
@@ -165,7 +194,7 @@ func TestPublicModule_Global(t *testing.T) {
{
Type: &GlobalType{ValType: ValueTypeF32},
Init: &ConstantExpression{Opcode: OpcodeF32Const,
Data: uint64Le(api.EncodeF32(1.0)),
Data: u64.LeBytes(api.EncodeF32(1.0)),
},
},
},
@@ -180,7 +209,7 @@ func TestPublicModule_Global(t *testing.T) {
{
Type: &GlobalType{ValType: ValueTypeF64},
Init: &ConstantExpression{Opcode: OpcodeF64Const,
Data: uint64Le(api.EncodeF64(1.0)),
Data: u64.LeBytes(api.EncodeF64(1.0)),
},
},
},
@@ -225,7 +254,7 @@ func TestPublicModule_Global(t *testing.T) {
{
Type: &GlobalType{ValType: ValueTypeF32, Mutable: true},
Init: &ConstantExpression{Opcode: OpcodeF32Const,
Data: uint64Le(api.EncodeF32(1.0)),
Data: u64.LeBytes(api.EncodeF32(1.0)),
},
},
},
@@ -242,7 +271,7 @@ func TestPublicModule_Global(t *testing.T) {
{
Type: &GlobalType{ValType: ValueTypeF64, Mutable: true},
Init: &ConstantExpression{Opcode: OpcodeF64Const,
Data: uint64Le(api.EncodeF64(1.0)),
Data: u64.LeBytes(api.EncodeF64(1.0)),
},
},
},
@@ -271,9 +300,3 @@ func TestPublicModule_Global(t *testing.T) {
})
}
}
func uint64Le(v uint64) (ret []byte) {
ret = make([]byte, 8)
gobinary.LittleEndian.PutUint64(ret, v)
return
}

View File

@@ -447,6 +447,8 @@ func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*Glo
gv = api.EncodeF32(v)
case float64:
gv = api.EncodeF64(v)
default:
panic(fmt.Errorf("BUG: invalid conversion %d", v))
}
globals = append(globals, &GlobalInstance{Type: gs.Type, Val: gv})
}

View File

@@ -1,7 +1,6 @@
package wasm
import (
"encoding/binary"
"fmt"
"math"
"reflect"
@@ -10,6 +9,8 @@ import (
"github.com/stretchr/testify/require"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/u64"
)
func TestFunctionType_String(t *testing.T) {
@@ -186,20 +187,19 @@ func TestValidateConstExpression(t *testing.T) {
for _, vt := range []ValueType{ValueTypeI32, ValueTypeI64, ValueTypeF32, ValueTypeF64} {
t.Run(ValueTypeName(vt), func(t *testing.T) {
t.Run("valid", func(t *testing.T) {
// Allocate bytes with enough size for all types.
expr := &ConstantExpression{Data: make([]byte, 8)}
expr := &ConstantExpression{}
switch vt {
case ValueTypeI32:
expr.Data[0] = 1
expr.Data = []byte{1}
expr.Opcode = OpcodeI32Const
case ValueTypeI64:
expr.Data[0] = 2
expr.Data = []byte{2}
expr.Opcode = OpcodeI64Const
case ValueTypeF32:
binary.LittleEndian.PutUint32(expr.Data, math.Float32bits(math.MaxFloat32))
expr.Data = u64.LeBytes(api.EncodeF32(math.MaxFloat32))
expr.Opcode = OpcodeF32Const
case ValueTypeF64:
binary.LittleEndian.PutUint64(expr.Data, math.Float64bits(math.MaxFloat64))
expr.Data = u64.LeBytes(api.EncodeF64(math.MaxFloat64))
expr.Opcode = OpcodeF64Const
}
@@ -661,32 +661,25 @@ func TestModule_validateExports(t *testing.T) {
}
func TestModule_buildGlobalInstances(t *testing.T) {
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint64(data, math.Float64bits(1.0))
m := Module{GlobalSection: []*Global{
{
Type: &GlobalType{Mutable: true, ValType: ValueTypeF64},
Init: &ConstantExpression{Opcode: OpcodeF64Const,
Data: []byte{0, 0, 0, 0, 0, 0, 0xf0, 0x3f}}, // == float64(1.0)
Data: u64.LeBytes(api.EncodeF64(math.MaxFloat64))},
},
{
Type: &GlobalType{Mutable: false, ValType: ValueTypeI32},
Init: &ConstantExpression{Opcode: OpcodeI32Const,
Data: []byte{1}},
Data: leb128.EncodeUint32(math.MaxInt32)},
},
}}
globals := m.buildGlobals(nil)
expectedGlobals := []*GlobalInstance{
{Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: math.Float64bits(1.0)},
{Type: &GlobalType{ValType: ValueTypeI32, Mutable: false}, Val: uint64(1)},
}
require.Len(t, globals, len(expectedGlobals))
for i := range globals {
actual, expected := globals[i], expectedGlobals[i]
require.Equal(t, expected, actual)
{Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: api.EncodeF64(math.MaxFloat64)},
{Type: &GlobalType{ValType: ValueTypeI32, Mutable: false}, Val: math.MaxInt32},
}
require.Equal(t, expectedGlobals, globals)
}
func TestModule_buildFunctionInstances(t *testing.T) {

View File

@@ -2,7 +2,6 @@ package wasm
import (
"context"
"encoding/binary"
"errors"
"fmt"
"math"
@@ -13,6 +12,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/testing/hammer"
"github.com/tetratelabs/wazero/internal/u64"
)
func TestModuleInstance_Memory(t *testing.T) {
@@ -466,20 +466,19 @@ func TestExecuteConstExpression(t *testing.T) {
t.Run("non global expr", func(t *testing.T) {
for _, vt := range []ValueType{ValueTypeI32, ValueTypeI64, ValueTypeF32, ValueTypeF64} {
t.Run(ValueTypeName(vt), func(t *testing.T) {
// Allocate bytes with enough size for all types.
expr := &ConstantExpression{Data: make([]byte, 8)}
expr := &ConstantExpression{}
switch vt {
case ValueTypeI32:
expr.Data[0] = 1
expr.Data = []byte{1}
expr.Opcode = OpcodeI32Const
case ValueTypeI64:
expr.Data[0] = 2
expr.Data = []byte{2}
expr.Opcode = OpcodeI64Const
case ValueTypeF32:
binary.LittleEndian.PutUint32(expr.Data, math.Float32bits(math.MaxFloat32))
expr.Data = u64.LeBytes(api.EncodeF32(math.MaxFloat32))
expr.Opcode = OpcodeF32Const
case ValueTypeF64:
binary.LittleEndian.PutUint64(expr.Data, math.Float64bits(math.MaxFloat64))
expr.Data = u64.LeBytes(api.EncodeF64(math.MaxFloat64))
expr.Opcode = OpcodeF64Const
}

View File

@@ -113,7 +113,7 @@ func (m *Module) validateTable() ([]*validatedElementSegment, error) {
ret = append(ret, &validatedElementSegment{oc, globalIdx, elem.Init})
} else if oc == OpcodeI32Const {
o, _, err := leb128.DecodeInt32(bytes.NewReader(elem.OffsetExpr.Data))
o, _, err := leb128.DecodeUint32(bytes.NewReader(elem.OffsetExpr.Data))
if err != nil {
return nil, fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/internal/wasm/binary"
"github.com/tetratelabs/wazero/internal/wasm/interpreter"
@@ -251,14 +252,14 @@ func addSpectestModule(t *testing.T, store *wasm.Store) {
// (global (export "global_f32") f32 (f32.const 666))
mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(666))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(666))},
})
mod.ExportSection["global_f32"] = &wasm.Export{Name: "global_f32", Index: 1, Type: wasm.ExternTypeGlobal}
// (global (export "global_f64") f64 (f64.const 666))
mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(666))},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(666))},
})
mod.ExportSection["global_f64"] = &wasm.Export{Name: "global_f64", Index: 2, Type: wasm.ExternTypeGlobal}