updated vendor

This commit is contained in:
2026-06-16 08:02:19 +02:00
parent 2f7f99d3f0
commit 77299d0c64
1283 changed files with 67302 additions and 208958 deletions
+86 -108
View File
@@ -6,18 +6,18 @@ import (
"sync"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
)
// Table describes the limits of elements and its type in a table.
type Table struct {
Min uint32
Max *uint32
Type RefType
Min uint32
Max *uint32
Type RefType
InitExpr *ConstantExpression
}
// RefType is either RefTypeFuncref or RefTypeExternref as of WebAssembly core 2.0.
type RefType = byte
// RefType is a reference type used for table elements.
type RefType = ValueType
const (
// RefTypeFuncref represents a reference to a function.
@@ -66,8 +66,8 @@ type ElementSegment struct {
// Followings are set/used regardless of the Mode.
// Init indices are (nullable) table elements where each index is the function index by which the module initialize the table.
Init []Index
// Init expressions are table elements where each expression evaluates to the function index by which the module initialize the table.
Init []ConstantExpression
// Type holds the type of this element segment, which is the RefType in WebAssembly 2.0.
Type RefType
@@ -76,39 +76,6 @@ type ElementSegment struct {
Mode ElementMode
}
const (
// ElementInitNullReference represents the null reference in ElementSegment's Init.
// In Wasm spec, an init item represents either Function's Index or null reference,
// and in wazero, we limit the maximum number of functions available in a module to
// MaximumFunctionIndex. Therefore, it is safe to use 1 << 31 to represent the null
// reference in Element segments.
ElementInitNullReference Index = 1 << 31
// elementInitImportedGlobalReferenceType represents an init item which is resolved via an imported global constexpr.
// The actual function reference stored at Global is only known at instantiation-time, so we set this flag
// to items of ElementSegment.Init at binary decoding, and unwrap this flag at instantiation to resolve the value.
//
// This might collide the init element resolved via ref.func instruction which is resolved with the func index at decoding,
// but in practice, that is not allowed in wazero thanks to our limit MaximumFunctionIndex. Thus, it is safe to set this flag
// in init element to indicate as such.
elementInitImportedGlobalReferenceType Index = 1 << 30
)
// unwrapElementInitGlobalReference takes an item of the init vector of an ElementSegment,
// and returns the Global index if it is supposed to get generated from a global.
// ok is true if the given init item is as such.
func unwrapElementInitGlobalReference(init Index) (_ Index, ok bool) {
if init&elementInitImportedGlobalReferenceType == elementInitImportedGlobalReferenceType {
return init &^ elementInitImportedGlobalReferenceType, true
}
return init, false
}
// WrapGlobalIndexAsElementInit wraps the given index as an init item which is resolved via an imported global value.
// See the comments on elementInitImportedGlobalReferenceType for more details.
func WrapGlobalIndexAsElementInit(init Index) Index {
return init | elementInitImportedGlobalReferenceType
}
// IsActive returns true if the element segment is "active" mode which requires the runtime to initialize table
// with the contents in .Init field.
func (e *ElementSegment) IsActive() bool {
@@ -174,20 +141,39 @@ func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []Table,
// Any offset applied is to the element, not the function index: validate here if the funcidx is sound.
for ei, init := range elem.Init {
if init == ElementInitNullReference {
continue
_, initType, err := evaluateConstExpr(
&init,
func(globalIndex Index) (ValueType, uint64, uint64, error) {
if globalIndex >= Index(globalsCount) {
return 0, 0, 0, fmt.Errorf("%s[%d].init[%d] global index %d out of range", SectionIDName(SectionIDElement), idx, ei, globalIndex)
}
vt, err := m.resolveConstExprGlobalType(enabledFeatures, SectionIDElement, idx, globalIndex)
return vt, 0, 0, err
},
func(funcIndex Index) (Reference, error) {
if funcIndex >= Index(funcCount) {
return 0, fmt.Errorf("%s[%d].init[%d] func index %d out of range", SectionIDName(SectionIDElement), idx, ei, funcIndex)
}
return 0, nil
},
)
if err != nil {
return err
}
index, ok := unwrapElementInitGlobalReference(init)
if ok {
if index >= globalsCount {
return fmt.Errorf("%s[%d].init[%d] global index %d out of range", SectionIDName(SectionIDElement), idx, ei, index)
switch elem.Type {
case RefTypeFuncref:
if initType != ValueTypeFuncref {
return fmt.Errorf("%s[%d].init[%d] must be funcref but was %s", SectionIDName(SectionIDElement), idx, ei, ValueTypeName(initType))
}
} else {
if elem.Type == RefTypeExternref {
return fmt.Errorf("%s[%d].init[%d] must be ref.null but was %d", SectionIDName(SectionIDElement), idx, ei, init)
case RefTypeExternref:
if initType != ValueTypeExternref {
return fmt.Errorf("%s[%d].init[%d] must be externref but was %s", SectionIDName(SectionIDElement), idx, ei, ValueTypeName(initType))
}
if index >= funcCount {
return fmt.Errorf("%s[%d].init[%d] func index %d out of range", SectionIDName(SectionIDElement), idx, ei, index)
default:
if !isRefSubtypeOf(initType, elem.Type) && initType != ValueTypeFuncref {
return fmt.Errorf("%s[%d].init[%d] must be %s but was %s",
SectionIDName(SectionIDElement), idx, ei, ValueTypeName(elem.Type), ValueTypeName(initType))
}
}
}
@@ -198,38 +184,49 @@ func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []Table,
}
t := tables[elem.TableIndex]
if t.Type != elem.Type {
if !isRefSubtypeOf(elem.Type, t.Type) {
return fmt.Errorf("element type mismatch: table has %s but element has %s",
RefTypeName(t.Type), RefTypeName(elem.Type),
)
}
// global.get needs to be discovered during initialization
oc := elem.OffsetExpr.Opcode
if oc == OpcodeGlobalGet {
globalIdx, _, err := leb128.LoadUint32(elem.OffsetExpr.Data)
if err != nil {
return fmt.Errorf("%s[%d] couldn't read global.get parameter: %w", SectionIDName(SectionIDElement), idx, err)
} else if err = m.verifyImportGlobalI32(SectionIDElement, idx, globalIdx); err != nil {
hasGlobalRef := false
offsetExprResults, offsetExprType, err := evaluateConstExpr(
&elem.OffsetExpr,
func(globalIndex Index) (ValueType, uint64, uint64, error) {
hasGlobalRef = true
if globalIndex >= Index(globalsCount) {
return 0, 0, 0, fmt.Errorf("%s[%d] global index %d out of range", SectionIDName(SectionIDElement), idx, globalIndex)
}
vt, err := m.resolveConstExprGlobalType(enabledFeatures, SectionIDElement, idx, globalIndex)
if err != nil {
return 0, 0, 0, err
}
if vt != ValueTypeI32 {
return 0, 0, 0, fmt.Errorf("%s[%d] (global.get %d): import[%d].global.ValType != i32", SectionIDName(SectionIDElement), idx, globalIndex, i)
}
return ValueTypeI32, 0, 0, nil
},
func(funcIndex Index) (Reference, error) {
return 0, nil
},
)
if err != nil {
return fmt.Errorf("%s[%d] couldn't evaluate offset expression: %w", SectionIDName(SectionIDElement), idx, err)
}
if offsetExprType != ValueTypeI32 {
return fmt.Errorf("%s[%d] offset expression must return i32 but was %s", SectionIDName(SectionIDElement), idx, ValueTypeName(offsetExprType))
}
if !enabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) && !hasGlobalRef && elem.TableIndex >= importedTableCount {
offset := uint32(offsetExprResults[0])
if err = checkSegmentBounds(t.Min, uint64(initCount)+uint64(offset), idx); err != nil {
return err
}
} else if oc == OpcodeI32Const {
// Per https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L117 we must pass if imported
// table has set its min=0. Per https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L142, we
// have to do fail if module-defined min=0.
if !enabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) && elem.TableIndex >= importedTableCount {
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
o, _, err := leb128.LoadInt32(elem.OffsetExpr.Data)
if err != nil {
return fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
}
offset := Index(o)
if err = checkSegmentBounds(t.Min, uint64(initCount)+uint64(offset), idx); err != nil {
return err
}
}
} else {
return fmt.Errorf("%s[%d] has an invalid const expression: %s", SectionIDName(SectionIDElement), idx, InstructionName(oc))
}
}
}
@@ -247,11 +244,20 @@ func (m *ModuleInstance) buildTables(module *Module, skipBoundCheck bool) (err e
idx := module.ImportTableCount
for i := range module.TableSection {
tsec := &module.TableSection[i]
// The module defining the table is the one that sets its Min/Max etc.
m.Tables[idx] = &TableInstance{
t := &TableInstance{
References: make([]Reference, tsec.Min), Min: tsec.Min, Max: tsec.Max,
Type: tsec.Type,
}
if tsec.InitExpr != nil {
initVals := evaluateConstExprInModuleInstance(tsec.InitExpr, m)
if len(initVals) > 0 && initVals[0] != 0 {
initRef := Reference(initVals[0])
for j := range t.References {
t.References[j] = initRef
}
}
}
m.Tables[idx] = t
idx++
}
@@ -259,18 +265,7 @@ func (m *ModuleInstance) buildTables(module *Module, skipBoundCheck bool) (err e
for elemI := range module.ElementSection { // Do not loop over the value since elementSegments is a slice of value.
elem := &module.ElementSection[elemI]
table := m.Tables[elem.TableIndex]
var offset uint32
if elem.OffsetExpr.Opcode == OpcodeGlobalGet {
// Ignore error as it's already validated.
globalIdx, _, _ := leb128.LoadUint32(elem.OffsetExpr.Data)
global := m.Globals[globalIdx]
offset = uint32(global.Val)
} else { // i32.const
// Ignore error as it's already validated.
o, _, _ := leb128.LoadInt32(elem.OffsetExpr.Data)
offset = uint32(o)
}
offset := uint32(evaluateConstExprInModuleInstance(&elem.OffsetExpr, m)[0])
// Check to see if we are out-of-bounds
initCount := uint64(len(elem.Init))
if err = checkSegmentBounds(table.Min, uint64(offset)+initCount, Index(elemI)); err != nil {
@@ -295,23 +290,6 @@ func checkSegmentBounds(min uint32, requireMin uint64, idx Index) error { // uin
return nil
}
func (m *Module) verifyImportGlobalI32(sectionID SectionID, sectionIdx Index, idx uint32) error {
ig := uint32(math.MaxUint32) // +1 == 0
for i := range m.ImportSection {
imp := &m.ImportSection[i]
if imp.Type == ExternTypeGlobal {
ig++
if ig == idx {
if imp.DescGlobal.ValType != ValueTypeI32 {
return fmt.Errorf("%s[%d] (global.get %d): import[%d].global.ValType != i32", SectionIDName(sectionID), sectionIdx, idx, i)
}
return nil
}
}
}
return fmt.Errorf("%s[%d] (global.get %d): out of range of imported globals", SectionIDName(sectionID), sectionIdx, idx)
}
// Grow appends the `initialRef` by `delta` times into the References slice.
// Returns -1 if the operation is not valid, otherwise the old length of the table.
//