github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/module.go (about)

     1  package wasm
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/bananabytelabs/wazero/api"
    15  	"github.com/bananabytelabs/wazero/experimental"
    16  	"github.com/bananabytelabs/wazero/internal/ieee754"
    17  	"github.com/bananabytelabs/wazero/internal/leb128"
    18  	"github.com/bananabytelabs/wazero/internal/wasmdebug"
    19  )
    20  
    21  // Module is a WebAssembly binary representation.
    22  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8
    23  //
    24  // Differences from the specification:
    25  // * NameSection is the only key ("name") decoded from the SectionIDCustom.
    26  // * ExportSection is represented as a map for lookup convenience.
    27  // * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not.
    28  type Module struct {
    29  	// TypeSection contains the unique FunctionType of functions imported or defined in this module.
    30  	//
    31  	// Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type.
    32  	// In the future, other types may be introduced to support CoreFeatures such as module linking.
    33  	//
    34  	// Note: In the Binary Format, this is SectionIDType.
    35  	//
    36  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0
    37  	TypeSection []FunctionType
    38  
    39  	// ImportSection contains imported functions, tables, memories or globals required for instantiation
    40  	// (Store.Instantiate).
    41  	//
    42  	// Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name.
    43  	//
    44  	// Note: In the Binary Format, this is SectionIDImport.
    45  	//
    46  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
    47  	ImportSection []Import
    48  	// ImportFunctionCount ImportGlobalCount ImportMemoryCount, and ImportTableCount are
    49  	// the cached import count per ExternType set during decoding.
    50  	ImportFunctionCount,
    51  	ImportGlobalCount,
    52  	ImportMemoryCount,
    53  	ImportTableCount Index
    54  	// ImportPerModule maps a module name to the list of Import to be imported from the module.
    55  	// This is used to do fast import resolution during instantiation.
    56  	ImportPerModule map[string][]*Import
    57  
    58  	// FunctionSection contains the index in TypeSection of each function defined in this module.
    59  	//
    60  	// Note: The function Index space begins with imported functions and ends with those defined in this module.
    61  	// For example, if there are two imported functions and one defined in this module, the function Index 3 is defined
    62  	// in this module at FunctionSection[0].
    63  	//
    64  	// Note: FunctionSection is index correlated with the CodeSection. If given the same position, e.g. 2, a function
    65  	// type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2].
    66  	//
    67  	// Note: In the Binary Format, this is SectionIDFunction.
    68  	//
    69  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
    70  	FunctionSection []Index
    71  
    72  	// TableSection contains each table defined in this module.
    73  	//
    74  	// Note: The table Index space begins with imported tables and ends with those defined in this module.
    75  	// For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in
    76  	// this module at TableSection[0].
    77  	//
    78  	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one table definition per module, so the
    79  	// length of the TableSection can be zero or one, and can only be one if there is no imported table.
    80  	//
    81  	// Note: In the Binary Format, this is SectionIDTable.
    82  	//
    83  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
    84  	TableSection []Table
    85  
    86  	// MemorySection contains each memory defined in this module.
    87  	//
    88  	// Note: The memory Index space begins with imported memories and ends with those defined in this module.
    89  	// For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in
    90  	// this module at TableSection[0].
    91  	//
    92  	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory definition per module, so the
    93  	// length of the MemorySection can be zero or one, and can only be one if there is no imported memory.
    94  	//
    95  	// Note: In the Binary Format, this is SectionIDMemory.
    96  	//
    97  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
    98  	MemorySection *Memory
    99  
   100  	// GlobalSection contains each global defined in this module.
   101  	//
   102  	// Global indexes are offset by any imported globals because the global index begins with imports, followed by
   103  	// ones defined in this module. For example, if there are two imported globals and three defined in this module, the
   104  	// global at index 3 is defined in this module at GlobalSection[0].
   105  	//
   106  	// Note: In the Binary Format, this is SectionIDGlobal.
   107  	//
   108  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
   109  	GlobalSection []Global
   110  
   111  	// ExportSection contains each export defined in this module.
   112  	//
   113  	// Note: In the Binary Format, this is SectionIDExport.
   114  	//
   115  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
   116  	ExportSection []Export
   117  	// Exports maps a name to Export, and is convenient for fast look up of exported instances at runtime.
   118  	// Each item of this map points to an element of ExportSection.
   119  	Exports map[string]*Export
   120  
   121  	// StartSection is the index of a function to call before returning from Store.Instantiate.
   122  	//
   123  	// Note: The index here is not the position in the FunctionSection, rather in the function index, which
   124  	// begins with imported functions.
   125  	//
   126  	// Note: In the Binary Format, this is SectionIDStart.
   127  	//
   128  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
   129  	StartSection *Index
   130  
   131  	// Note: In the Binary Format, this is SectionIDElement.
   132  	ElementSection []ElementSegment
   133  
   134  	// CodeSection is index-correlated with FunctionSection and contains each
   135  	// function's locals and body.
   136  	//
   137  	// When present, the HostFunctionSection of the same index must be nil.
   138  	//
   139  	// Note: In the Binary Format, this is SectionIDCode.
   140  	//
   141  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
   142  	CodeSection []Code
   143  
   144  	// Note: In the Binary Format, this is SectionIDData.
   145  	DataSection []DataSegment
   146  
   147  	// NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format.
   148  	//
   149  	// Note: This is the only SectionIDCustom defined in the WebAssembly 1.0 (20191205) Binary Format.
   150  	// Others are skipped as they are not used in wazero.
   151  	//
   152  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
   153  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
   154  	NameSection *NameSection
   155  
   156  	// CustomSections are set when the SectionIDCustom other than "name" were successfully decoded from the binary format.
   157  	//
   158  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
   159  	CustomSections []*CustomSection
   160  
   161  	// DataCountSection is the optional section and holds the number of data segments in the data section.
   162  	//
   163  	// Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations.
   164  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
   165  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   166  	DataCountSection *uint32
   167  
   168  	// ID is the sha256 value of the source wasm plus the configurations which affect the runtime representation of
   169  	// Wasm binary. This is only used for caching.
   170  	ID ModuleID
   171  
   172  	// IsHostModule true if this is the host module, false otherwise.
   173  	IsHostModule bool
   174  
   175  	// functionDefinitionSectionInitOnce guards FunctionDefinitionSection so that it is initialized exactly once.
   176  	functionDefinitionSectionInitOnce sync.Once
   177  
   178  	// FunctionDefinitionSection is a wazero-specific section.
   179  	FunctionDefinitionSection []FunctionDefinition
   180  
   181  	// MemoryDefinitionSection is a wazero-specific section.
   182  	MemoryDefinitionSection []MemoryDefinition
   183  
   184  	// DWARFLines is used to emit DWARF based stack trace. This is created from the multiple custom sections
   185  	// as described in https://yurydelendik.github.io/webassembly-dwarf/, though it is not specified in the Wasm
   186  	// specification: https://github.com/WebAssembly/debugging/issues/1
   187  	DWARFLines *wasmdebug.DWARFLines
   188  }
   189  
   190  // ModuleID represents sha256 hash value uniquely assigned to Module.
   191  type ModuleID = [sha256.Size]byte
   192  
   193  // The wazero specific limitation described at RATIONALE.md.
   194  // TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max
   195  const (
   196  	MaximumGlobals       = uint32(1 << 27)
   197  	MaximumFunctionIndex = uint32(1 << 27)
   198  	MaximumTableIndex    = uint32(1 << 27)
   199  )
   200  
   201  // AssignModuleID calculates a sha256 checksum on `wasm` and other args, and set Module.ID to the result.
   202  // See the doc on Module.ID on what it's used for.
   203  func (m *Module) AssignModuleID(wasm []byte, listeners []experimental.FunctionListener, withEnsureTermination bool) {
   204  	h := sha256.New()
   205  	h.Write(wasm)
   206  	// Use the pre-allocated space backed by m.ID below.
   207  
   208  	// Write the existence of listeners to the checksum per function.
   209  	for i, l := range listeners {
   210  		binary.LittleEndian.PutUint32(m.ID[:], uint32(i))
   211  		m.ID[4] = boolToByte(l != nil)
   212  		h.Write(m.ID[:5])
   213  	}
   214  	// Write the flag of ensureTermination to the checksum.
   215  	m.ID[0] = boolToByte(withEnsureTermination)
   216  	h.Write(m.ID[:1])
   217  	// Get checksum by passing the slice underlying m.ID.
   218  	h.Sum(m.ID[:0])
   219  }
   220  
   221  func boolToByte(b bool) (ret byte) {
   222  	if b {
   223  		ret = 1
   224  	}
   225  	return
   226  }
   227  
   228  // typeOfFunction returns the wasm.FunctionType for the given function space index or nil.
   229  func (m *Module) typeOfFunction(funcIdx Index) *FunctionType {
   230  	typeSectionLength, importedFunctionCount := uint32(len(m.TypeSection)), m.ImportFunctionCount
   231  	if funcIdx < importedFunctionCount {
   232  		// Imports are not exclusively functions. This is the current function index in the loop.
   233  		cur := Index(0)
   234  		for i := range m.ImportSection {
   235  			imp := &m.ImportSection[i]
   236  			if imp.Type != ExternTypeFunc {
   237  				continue
   238  			}
   239  			if funcIdx == cur {
   240  				if imp.DescFunc >= typeSectionLength {
   241  					return nil
   242  				}
   243  				return &m.TypeSection[imp.DescFunc]
   244  			}
   245  			cur++
   246  		}
   247  	}
   248  
   249  	funcSectionIdx := funcIdx - m.ImportFunctionCount
   250  	if funcSectionIdx >= uint32(len(m.FunctionSection)) {
   251  		return nil
   252  	}
   253  	typeIdx := m.FunctionSection[funcSectionIdx]
   254  	if typeIdx >= typeSectionLength {
   255  		return nil
   256  	}
   257  	return &m.TypeSection[typeIdx]
   258  }
   259  
   260  func (m *Module) Validate(enabledFeatures api.CoreFeatures) error {
   261  	for i := range m.TypeSection {
   262  		tp := &m.TypeSection[i]
   263  		tp.CacheNumInUint64()
   264  	}
   265  
   266  	if err := m.validateStartSection(); err != nil {
   267  		return err
   268  	}
   269  
   270  	functions, globals, memory, tables, err := m.AllDeclarations()
   271  	if err != nil {
   272  		return err
   273  	}
   274  
   275  	if err = m.validateImports(enabledFeatures); err != nil {
   276  		return err
   277  	}
   278  
   279  	if err = m.validateGlobals(globals, uint32(len(functions)), MaximumGlobals); err != nil {
   280  		return err
   281  	}
   282  
   283  	if err = m.validateMemory(memory, globals, enabledFeatures); err != nil {
   284  		return err
   285  	}
   286  
   287  	if err = m.validateExports(enabledFeatures, functions, globals, memory, tables); err != nil {
   288  		return err
   289  	}
   290  
   291  	if m.CodeSection != nil {
   292  		if err = m.validateFunctions(enabledFeatures, functions, globals, memory, tables, MaximumFunctionIndex); err != nil {
   293  			return err
   294  		}
   295  	} // No need to validate host functions as NewHostModule validates
   296  
   297  	if err = m.validateTable(enabledFeatures, tables, MaximumTableIndex); err != nil {
   298  		return err
   299  	}
   300  
   301  	if err = m.validateDataCountSection(); err != nil {
   302  		return err
   303  	}
   304  	return nil
   305  }
   306  
   307  func (m *Module) validateStartSection() error {
   308  	// Check the start function is valid.
   309  	// TODO: this should be verified during decode so that errors have the correct source positions
   310  	if m.StartSection != nil {
   311  		startIndex := *m.StartSection
   312  		ft := m.typeOfFunction(startIndex)
   313  		if ft == nil { // TODO: move this check to decoder so that a module can never be decoded invalidly
   314  			return fmt.Errorf("invalid start function: func[%d] has an invalid type", startIndex)
   315  		}
   316  		if len(ft.Params) > 0 || len(ft.Results) > 0 {
   317  			return fmt.Errorf("invalid start function: func[%d] must have an empty (nullary) signature: %s", startIndex, ft)
   318  		}
   319  	}
   320  	return nil
   321  }
   322  
   323  func (m *Module) validateGlobals(globals []GlobalType, numFuncts, maxGlobals uint32) error {
   324  	if uint32(len(globals)) > maxGlobals {
   325  		return fmt.Errorf("too many globals in a module")
   326  	}
   327  
   328  	// Global initialization constant expression can only reference the imported globals.
   329  	// See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
   330  	importedGlobals := globals[:m.ImportGlobalCount]
   331  	for i := range m.GlobalSection {
   332  		g := &m.GlobalSection[i]
   333  		if err := validateConstExpression(importedGlobals, numFuncts, &g.Init, g.Type.ValType); err != nil {
   334  			return err
   335  		}
   336  	}
   337  	return nil
   338  }
   339  
   340  func (m *Module) validateFunctions(enabledFeatures api.CoreFeatures, functions []Index, globals []GlobalType, memory *Memory, tables []Table, maximumFunctionIndex uint32) error {
   341  	if uint32(len(functions)) > maximumFunctionIndex {
   342  		return fmt.Errorf("too many functions (%d) in a module", len(functions))
   343  	}
   344  
   345  	functionCount := m.SectionElementCount(SectionIDFunction)
   346  	codeCount := m.SectionElementCount(SectionIDCode)
   347  	if functionCount == 0 && codeCount == 0 {
   348  		return nil
   349  	}
   350  
   351  	typeCount := m.SectionElementCount(SectionIDType)
   352  	if codeCount != functionCount {
   353  		return fmt.Errorf("code count (%d) != function count (%d)", codeCount, functionCount)
   354  	}
   355  
   356  	declaredFuncIndexes, err := m.declaredFunctionIndexes()
   357  	if err != nil {
   358  		return err
   359  	}
   360  
   361  	// Create bytes.Reader once as it causes allocation, and
   362  	// we frequently need it (e.g. on every If instruction).
   363  	br := bytes.NewReader(nil)
   364  	// Also, we reuse the stacks across multiple function validations to reduce allocations.
   365  	vs := &stacks{}
   366  	for idx, typeIndex := range m.FunctionSection {
   367  		if typeIndex >= typeCount {
   368  			return fmt.Errorf("invalid %s: type section index %d out of range", m.funcDesc(SectionIDFunction, Index(idx)), typeIndex)
   369  		}
   370  		c := &m.CodeSection[idx]
   371  		if c.GoFunc != nil {
   372  			continue
   373  		}
   374  		if err = m.validateFunction(vs, enabledFeatures, Index(idx), functions, globals, memory, tables, declaredFuncIndexes, br); err != nil {
   375  			return fmt.Errorf("invalid %s: %w", m.funcDesc(SectionIDFunction, Index(idx)), err)
   376  		}
   377  	}
   378  	return nil
   379  }
   380  
   381  // declaredFunctionIndexes returns a set of function indexes that can be used as an immediate for OpcodeRefFunc instruction.
   382  //
   383  // The criteria for which function indexes can be available for that instruction is vague in the spec:
   384  //
   385  //   - "References: the list of function indices that occur in the module outside functions and can hence be used to form references inside them."
   386  //   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/conventions.html#contexts
   387  //   - "Ref is the set funcidx(module with functions=ε, start=ε) , i.e., the set of function indices occurring in the module, except in its functions or start function."
   388  //   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/modules.html#valid-module
   389  //
   390  // To clarify, we reverse-engineer logic required to pass the WebAssembly Core specification 2.0 test suite:
   391  // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/ref_func.wast#L78-L115
   392  //
   393  // To summarize, the function indexes OpcodeRefFunc can refer include:
   394  //   - existing in an element section regardless of its mode (active, passive, declarative).
   395  //   - defined as globals whose value type is ValueRefFunc.
   396  //   - used as an exported function.
   397  //
   398  // See https://github.com/WebAssembly/reference-types/issues/31
   399  // See https://github.com/WebAssembly/reference-types/issues/76
   400  func (m *Module) declaredFunctionIndexes() (ret map[Index]struct{}, err error) {
   401  	ret = map[uint32]struct{}{}
   402  
   403  	for i := range m.ExportSection {
   404  		exp := &m.ExportSection[i]
   405  		if exp.Type == ExternTypeFunc {
   406  			ret[exp.Index] = struct{}{}
   407  		}
   408  	}
   409  
   410  	for i := range m.GlobalSection {
   411  		g := &m.GlobalSection[i]
   412  		if g.Init.Opcode == OpcodeRefFunc {
   413  			var index uint32
   414  			index, _, err = leb128.LoadUint32(g.Init.Data)
   415  			if err != nil {
   416  				err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err)
   417  				return
   418  			}
   419  			ret[index] = struct{}{}
   420  		}
   421  	}
   422  
   423  	for i := range m.ElementSection {
   424  		elem := &m.ElementSection[i]
   425  		for _, index := range elem.Init {
   426  			if index != ElementInitNullReference {
   427  				ret[index] = struct{}{}
   428  			}
   429  		}
   430  	}
   431  	return
   432  }
   433  
   434  func (m *Module) funcDesc(sectionID SectionID, sectionIndex Index) string {
   435  	// Try to improve the error message by collecting any exports:
   436  	var exportNames []string
   437  	funcIdx := sectionIndex + m.ImportFunctionCount
   438  	for i := range m.ExportSection {
   439  		exp := &m.ExportSection[i]
   440  		if exp.Index == funcIdx && exp.Type == ExternTypeFunc {
   441  			exportNames = append(exportNames, fmt.Sprintf("%q", exp.Name))
   442  		}
   443  	}
   444  	sectionIDName := SectionIDName(sectionID)
   445  	if exportNames == nil {
   446  		return fmt.Sprintf("%s[%d]", sectionIDName, sectionIndex)
   447  	}
   448  	sort.Strings(exportNames) // go map keys do not iterate consistently
   449  	return fmt.Sprintf("%s[%d] export[%s]", sectionIDName, sectionIndex, strings.Join(exportNames, ","))
   450  }
   451  
   452  func (m *Module) validateMemory(memory *Memory, globals []GlobalType, _ api.CoreFeatures) error {
   453  	var activeElementCount int
   454  	for i := range m.DataSection {
   455  		d := &m.DataSection[i]
   456  		if !d.IsPassive() {
   457  			activeElementCount++
   458  		}
   459  	}
   460  	if activeElementCount > 0 && memory == nil {
   461  		return fmt.Errorf("unknown memory")
   462  	}
   463  
   464  	// Constant expression can only reference imported globals.
   465  	// https://github.com/WebAssembly/spec/blob/5900d839f38641989a9d8df2df4aee0513365d39/test/core/data.wast#L84-L91
   466  	importedGlobals := globals[:m.ImportGlobalCount]
   467  	for i := range m.DataSection {
   468  		d := &m.DataSection[i]
   469  		if !d.IsPassive() {
   470  			if err := validateConstExpression(importedGlobals, 0, &d.OffsetExpression, ValueTypeI32); err != nil {
   471  				return fmt.Errorf("calculate offset: %w", err)
   472  			}
   473  		}
   474  	}
   475  	return nil
   476  }
   477  
   478  func (m *Module) validateImports(enabledFeatures api.CoreFeatures) error {
   479  	for i := range m.ImportSection {
   480  		imp := &m.ImportSection[i]
   481  		if imp.Module == "" {
   482  			return fmt.Errorf("import[%d] has an empty module name", i)
   483  		}
   484  		switch imp.Type {
   485  		case ExternTypeFunc:
   486  			if int(imp.DescFunc) >= len(m.TypeSection) {
   487  				return fmt.Errorf("invalid import[%q.%q] function: type index out of range", imp.Module, imp.Name)
   488  			}
   489  		case ExternTypeGlobal:
   490  			if !imp.DescGlobal.Mutable {
   491  				continue
   492  			}
   493  			if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil {
   494  				return fmt.Errorf("invalid import[%q.%q] global: %w", imp.Module, imp.Name, err)
   495  			}
   496  		}
   497  	}
   498  	return nil
   499  }
   500  
   501  func (m *Module) validateExports(enabledFeatures api.CoreFeatures, functions []Index, globals []GlobalType, memory *Memory, tables []Table) error {
   502  	for i := range m.ExportSection {
   503  		exp := &m.ExportSection[i]
   504  		index := exp.Index
   505  		switch exp.Type {
   506  		case ExternTypeFunc:
   507  			if index >= uint32(len(functions)) {
   508  				return fmt.Errorf("unknown function for export[%q]", exp.Name)
   509  			}
   510  		case ExternTypeGlobal:
   511  			if index >= uint32(len(globals)) {
   512  				return fmt.Errorf("unknown global for export[%q]", exp.Name)
   513  			}
   514  			if !globals[index].Mutable {
   515  				continue
   516  			}
   517  			if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil {
   518  				return fmt.Errorf("invalid export[%q] global[%d]: %w", exp.Name, index, err)
   519  			}
   520  		case ExternTypeMemory:
   521  			if index > 0 || memory == nil {
   522  				return fmt.Errorf("memory for export[%q] out of range", exp.Name)
   523  			}
   524  		case ExternTypeTable:
   525  			if index >= uint32(len(tables)) {
   526  				return fmt.Errorf("table for export[%q] out of range", exp.Name)
   527  			}
   528  		}
   529  	}
   530  	return nil
   531  }
   532  
   533  func validateConstExpression(globals []GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) {
   534  	var actualType ValueType
   535  	switch expr.Opcode {
   536  	case OpcodeI32Const:
   537  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
   538  		_, _, err = leb128.LoadInt32(expr.Data)
   539  		if err != nil {
   540  			return fmt.Errorf("read i32: %w", err)
   541  		}
   542  		actualType = ValueTypeI32
   543  	case OpcodeI64Const:
   544  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
   545  		_, _, err = leb128.LoadInt64(expr.Data)
   546  		if err != nil {
   547  			return fmt.Errorf("read i64: %w", err)
   548  		}
   549  		actualType = ValueTypeI64
   550  	case OpcodeF32Const:
   551  		_, err = ieee754.DecodeFloat32(expr.Data)
   552  		if err != nil {
   553  			return fmt.Errorf("read f32: %w", err)
   554  		}
   555  		actualType = ValueTypeF32
   556  	case OpcodeF64Const:
   557  		_, err = ieee754.DecodeFloat64(expr.Data)
   558  		if err != nil {
   559  			return fmt.Errorf("read f64: %w", err)
   560  		}
   561  		actualType = ValueTypeF64
   562  	case OpcodeGlobalGet:
   563  		id, _, err := leb128.LoadUint32(expr.Data)
   564  		if err != nil {
   565  			return fmt.Errorf("read index of global: %w", err)
   566  		}
   567  		if uint32(len(globals)) <= id {
   568  			return fmt.Errorf("global index out of range")
   569  		}
   570  		actualType = globals[id].ValType
   571  	case OpcodeRefNull:
   572  		if len(expr.Data) == 0 {
   573  			return fmt.Errorf("read reference type for ref.null: %w", io.ErrShortBuffer)
   574  		}
   575  		reftype := expr.Data[0]
   576  		if reftype != RefTypeFuncref && reftype != RefTypeExternref {
   577  			return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
   578  		}
   579  		actualType = reftype
   580  	case OpcodeRefFunc:
   581  		index, _, err := leb128.LoadUint32(expr.Data)
   582  		if err != nil {
   583  			return fmt.Errorf("read i32: %w", err)
   584  		} else if index >= numFuncs {
   585  			return fmt.Errorf("ref.func index out of range [%d] with length %d", index, numFuncs-1)
   586  		}
   587  		actualType = ValueTypeFuncref
   588  	case OpcodeVecV128Const:
   589  		if len(expr.Data) != 16 {
   590  			return fmt.Errorf("%s needs 16 bytes but was %d bytes", OpcodeVecV128ConstName, len(expr.Data))
   591  		}
   592  		actualType = ValueTypeV128
   593  	default:
   594  		return fmt.Errorf("invalid opcode for const expression: 0x%x", expr.Opcode)
   595  	}
   596  
   597  	if actualType != expectedType {
   598  		return fmt.Errorf("const expression type mismatch expected %s but got %s",
   599  			ValueTypeName(expectedType), ValueTypeName(actualType))
   600  	}
   601  	return nil
   602  }
   603  
   604  func (m *Module) validateDataCountSection() (err error) {
   605  	if m.DataCountSection != nil && int(*m.DataCountSection) != len(m.DataSection) {
   606  		err = fmt.Errorf("data count section (%d) doesn't match the length of data section (%d)",
   607  			*m.DataCountSection, len(m.DataSection))
   608  	}
   609  	return
   610  }
   611  
   612  func (m *ModuleInstance) buildGlobals(module *Module, funcRefResolver func(funcIndex Index) Reference) {
   613  	importedGlobals := m.Globals[:module.ImportGlobalCount]
   614  
   615  	me := m.Engine
   616  	engineOwnGlobal := me.OwnsGlobals()
   617  	for i := Index(0); i < Index(len(module.GlobalSection)); i++ {
   618  		gs := &module.GlobalSection[i]
   619  		g := &GlobalInstance{}
   620  		if engineOwnGlobal {
   621  			g.Me = me
   622  			g.Index = i + module.ImportGlobalCount
   623  		}
   624  		m.Globals[i+module.ImportGlobalCount] = g
   625  		g.Type = gs.Type
   626  		g.initialize(importedGlobals, &gs.Init, funcRefResolver)
   627  	}
   628  }
   629  
   630  func paramNames(localNames IndirectNameMap, funcIdx uint32, paramLen int) []string {
   631  	for i := range localNames {
   632  		nm := &localNames[i]
   633  		// Only build parameter names if we have one for each.
   634  		if nm.Index != funcIdx || len(nm.NameMap) < paramLen {
   635  			continue
   636  		}
   637  
   638  		ret := make([]string, paramLen)
   639  		for j := range nm.NameMap {
   640  			p := &nm.NameMap[j]
   641  			if int(p.Index) < paramLen {
   642  				ret[p.Index] = p.Name
   643  			}
   644  		}
   645  		return ret
   646  	}
   647  	return nil
   648  }
   649  
   650  func (m *ModuleInstance) buildMemory(module *Module) {
   651  	memSec := module.MemorySection
   652  	if memSec != nil {
   653  		m.MemoryInstance = NewMemoryInstance(memSec)
   654  		m.MemoryInstance.definition = &module.MemoryDefinitionSection[0]
   655  	}
   656  }
   657  
   658  // Index is the offset in an index, not necessarily an absolute position in a Module section. This is because
   659  // indexs are often preceded by a corresponding type in the Module.ImportSection.
   660  //
   661  // For example, the function index starts with any ExternTypeFunc in the Module.ImportSection followed by
   662  // the Module.FunctionSection
   663  //
   664  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index
   665  type Index = uint32
   666  
   667  // FunctionType is a possibly empty function signature.
   668  //
   669  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0
   670  type FunctionType struct {
   671  	// Params are the possibly empty sequence of value types accepted by a function with this signature.
   672  	Params []ValueType
   673  
   674  	// Results are the possibly empty sequence of value types returned by a function with this signature.
   675  	//
   676  	// Note: In WebAssembly 1.0 (20191205), there can be at most one result.
   677  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
   678  	Results []ValueType
   679  
   680  	// string is cached as it is used both for String and key
   681  	string string
   682  
   683  	// ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type.
   684  	ParamNumInUint64 int
   685  
   686  	// ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type.
   687  	ResultNumInUint64 int
   688  }
   689  
   690  func (f *FunctionType) CacheNumInUint64() {
   691  	if f.ParamNumInUint64 == 0 {
   692  		for _, tp := range f.Params {
   693  			f.ParamNumInUint64++
   694  			if tp == ValueTypeV128 {
   695  				f.ParamNumInUint64++
   696  			}
   697  		}
   698  	}
   699  
   700  	if f.ResultNumInUint64 == 0 {
   701  		for _, tp := range f.Results {
   702  			f.ResultNumInUint64++
   703  			if tp == ValueTypeV128 {
   704  				f.ResultNumInUint64++
   705  			}
   706  		}
   707  	}
   708  }
   709  
   710  // EqualsSignature returns true if the function type has the same parameters and results.
   711  func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool {
   712  	return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results)
   713  }
   714  
   715  // key gets or generates the key for Store.typeIDs. e.g. "i32_v" for one i32 parameter and no (void) result.
   716  func (f *FunctionType) key() string {
   717  	if f.string != "" {
   718  		return f.string
   719  	}
   720  	var ret string
   721  	for _, b := range f.Params {
   722  		ret += ValueTypeName(b)
   723  	}
   724  	if len(f.Params) == 0 {
   725  		ret += "v_"
   726  	} else {
   727  		ret += "_"
   728  	}
   729  	for _, b := range f.Results {
   730  		ret += ValueTypeName(b)
   731  	}
   732  	if len(f.Results) == 0 {
   733  		ret += "v"
   734  	}
   735  	f.string = ret
   736  	return ret
   737  }
   738  
   739  // String implements fmt.Stringer.
   740  func (f *FunctionType) String() string {
   741  	return f.key()
   742  }
   743  
   744  // Import is the binary representation of an import indicated by Type
   745  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import
   746  type Import struct {
   747  	Type ExternType
   748  	// Module is the possibly empty primary namespace of this import
   749  	Module string
   750  	// Module is the possibly empty secondary namespace of this import
   751  	Name string
   752  	// DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc
   753  	DescFunc Index
   754  	// DescTable is the inlined Table when Type equals ExternTypeTable
   755  	DescTable Table
   756  	// DescMem is the inlined Memory when Type equals ExternTypeMemory
   757  	DescMem *Memory
   758  	// DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal
   759  	DescGlobal GlobalType
   760  	// IndexPerType has the index of this import per ExternType.
   761  	IndexPerType Index
   762  }
   763  
   764  // Memory describes the limits of pages (64KB) in a memory.
   765  type Memory struct {
   766  	Min, Cap, Max uint32
   767  	// IsMaxEncoded true if the Max is encoded in the original binary.
   768  	IsMaxEncoded bool
   769  }
   770  
   771  // Validate ensures values assigned to Min, Cap and Max are within valid thresholds.
   772  func (m *Memory) Validate(memoryLimitPages uint32) error {
   773  	min, capacity, max := m.Min, m.Cap, m.Max
   774  
   775  	if max > memoryLimitPages {
   776  		return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)",
   777  			max, PagesToUnitOfBytes(max), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
   778  	} else if min > memoryLimitPages {
   779  		return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)",
   780  			min, PagesToUnitOfBytes(min), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
   781  	} else if min > max {
   782  		return fmt.Errorf("min %d pages (%s) > max %d pages (%s)",
   783  			min, PagesToUnitOfBytes(min), max, PagesToUnitOfBytes(max))
   784  	} else if capacity < min {
   785  		return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)",
   786  			capacity, PagesToUnitOfBytes(capacity), min, PagesToUnitOfBytes(min))
   787  	} else if capacity > memoryLimitPages {
   788  		return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)",
   789  			capacity, PagesToUnitOfBytes(capacity), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
   790  	}
   791  	return nil
   792  }
   793  
   794  type GlobalType struct {
   795  	ValType ValueType
   796  	Mutable bool
   797  }
   798  
   799  type Global struct {
   800  	Type GlobalType
   801  	Init ConstantExpression
   802  }
   803  
   804  type ConstantExpression struct {
   805  	Opcode Opcode
   806  	Data   []byte
   807  }
   808  
   809  // Export is the binary representation of an export indicated by Type
   810  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export
   811  type Export struct {
   812  	Type ExternType
   813  
   814  	// Name is what the host refers to this definition as.
   815  	Name string
   816  
   817  	// Index is the index of the definition to export, the index is by Type
   818  	// e.g. If ExternTypeFunc, this is a position in the function index.
   819  	Index Index
   820  }
   821  
   822  // Code is an entry in the Module.CodeSection containing the locals and body of the function.
   823  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
   824  type Code struct {
   825  	// LocalTypes are any function-scoped variables in insertion order.
   826  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local
   827  	LocalTypes []ValueType
   828  
   829  	// Body is a sequence of expressions ending in OpcodeEnd
   830  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr
   831  	Body []byte
   832  
   833  	// GoFunc is non-nil when IsHostFunction and defined in go, either
   834  	// api.GoFunction or api.GoModuleFunction. When present, LocalTypes and Body must
   835  	// be nil.
   836  	//
   837  	// Note: This has no serialization format, so is not encodable.
   838  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
   839  	GoFunc interface{}
   840  
   841  	// BodyOffsetInCodeSection is the offset of the beginning of the body in the code section.
   842  	// This is used for DWARF based stack trace where a program counter represents an offset in code section.
   843  	BodyOffsetInCodeSection uint64
   844  }
   845  
   846  type DataSegment struct {
   847  	OffsetExpression ConstantExpression
   848  	Init             []byte
   849  	Passive          bool
   850  }
   851  
   852  // IsPassive returns true if this data segment is "passive" in the sense that memory offset and
   853  // index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory
   854  // operations proposal.
   855  //
   856  // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   857  func (d *DataSegment) IsPassive() bool {
   858  	return d.Passive
   859  }
   860  
   861  // NameSection represent the known custom name subsections defined in the WebAssembly Binary Format
   862  //
   863  // Note: This can be nil if no names were decoded for any reason including configuration.
   864  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
   865  type NameSection struct {
   866  	// ModuleName is the symbolic identifier for a module. e.g. math
   867  	//
   868  	// Note: This can be empty for any reason including configuration.
   869  	ModuleName string
   870  
   871  	// FunctionNames is an association of a function index to its symbolic identifier. e.g. add
   872  	//
   873  	// * the key (idx) is in the function index, where module defined functions are preceded by imported ones.
   874  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7
   875  	//
   876  	// For example, assuming the below text format is the second import, you would expect FunctionNames[1] = "mul"
   877  	//	(import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
   878  	//
   879  	// Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index.
   880  	// Note: This can be nil for any reason including configuration.
   881  	FunctionNames NameMap
   882  
   883  	// LocalNames contains symbolic names for function parameters or locals that have one.
   884  	//
   885  	// Note: In the Text Format, function local names can inherit parameter
   886  	// names from their type. Here are some examples:
   887  	//  * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}]
   888  	//  * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]]
   889  	//  * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}]
   890  	//
   891  	// Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
   892  	// Note: This can be nil for any reason including configuration.
   893  	LocalNames IndirectNameMap
   894  
   895  	// ResultNames is a wazero-specific mechanism to store result names.
   896  	ResultNames IndirectNameMap
   897  }
   898  
   899  // CustomSection contains the name and raw data of a custom section.
   900  type CustomSection struct {
   901  	Name string
   902  	Data []byte
   903  }
   904  
   905  // NameMap associates an index with any associated names.
   906  //
   907  // Note: Often the index bridges multiple sections. For example, the function index starts with any
   908  // ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection
   909  //
   910  // Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique.
   911  // Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index
   912  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap
   913  type NameMap []NameAssoc
   914  
   915  type NameAssoc struct {
   916  	Index Index
   917  	Name  string
   918  }
   919  
   920  // IndirectNameMap associates an index with an association of names.
   921  //
   922  // Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique.
   923  // Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index
   924  // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap
   925  type IndirectNameMap []NameMapAssoc
   926  
   927  type NameMapAssoc struct {
   928  	Index   Index
   929  	NameMap NameMap
   930  }
   931  
   932  // AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones.
   933  func (m *Module) AllDeclarations() (functions []Index, globals []GlobalType, memory *Memory, tables []Table, err error) {
   934  	for i := range m.ImportSection {
   935  		imp := &m.ImportSection[i]
   936  		switch imp.Type {
   937  		case ExternTypeFunc:
   938  			functions = append(functions, imp.DescFunc)
   939  		case ExternTypeGlobal:
   940  			globals = append(globals, imp.DescGlobal)
   941  		case ExternTypeMemory:
   942  			memory = imp.DescMem
   943  		case ExternTypeTable:
   944  			tables = append(tables, imp.DescTable)
   945  		}
   946  	}
   947  
   948  	functions = append(functions, m.FunctionSection...)
   949  	for i := range m.GlobalSection {
   950  		g := &m.GlobalSection[i]
   951  		globals = append(globals, g.Type)
   952  	}
   953  	if m.MemorySection != nil {
   954  		if memory != nil { // shouldn't be possible due to Validate
   955  			err = errors.New("at most one table allowed in module")
   956  			return
   957  		}
   958  		memory = m.MemorySection
   959  	}
   960  	if m.TableSection != nil {
   961  		tables = append(tables, m.TableSection...)
   962  	}
   963  	return
   964  }
   965  
   966  // SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format.
   967  //
   968  // Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless
   969  // of format, and deferring to the binary type avoids confusion.
   970  //
   971  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   972  type SectionID = byte
   973  
   974  const (
   975  	// SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard.
   976  	SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   977  	SectionIDType
   978  	SectionIDImport
   979  	SectionIDFunction
   980  	SectionIDTable
   981  	SectionIDMemory
   982  	SectionIDGlobal
   983  	SectionIDExport
   984  	SectionIDStart
   985  	SectionIDElement
   986  	SectionIDCode
   987  	SectionIDData
   988  
   989  	// SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations enabled.
   990  	//
   991  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
   992  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   993  	SectionIDDataCount
   994  )
   995  
   996  // SectionIDName returns the canonical name of a module section.
   997  // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   998  func SectionIDName(sectionID SectionID) string {
   999  	switch sectionID {
  1000  	case SectionIDCustom:
  1001  		return "custom"
  1002  	case SectionIDType:
  1003  		return "type"
  1004  	case SectionIDImport:
  1005  		return "import"
  1006  	case SectionIDFunction:
  1007  		return "function"
  1008  	case SectionIDTable:
  1009  		return "table"
  1010  	case SectionIDMemory:
  1011  		return "memory"
  1012  	case SectionIDGlobal:
  1013  		return "global"
  1014  	case SectionIDExport:
  1015  		return "export"
  1016  	case SectionIDStart:
  1017  		return "start"
  1018  	case SectionIDElement:
  1019  		return "element"
  1020  	case SectionIDCode:
  1021  		return "code"
  1022  	case SectionIDData:
  1023  		return "data"
  1024  	case SectionIDDataCount:
  1025  		return "data_count"
  1026  	}
  1027  	return "unknown"
  1028  }
  1029  
  1030  // ValueType is an alias of api.ValueType defined to simplify imports.
  1031  type ValueType = api.ValueType
  1032  
  1033  const (
  1034  	ValueTypeI32 = api.ValueTypeI32
  1035  	ValueTypeI64 = api.ValueTypeI64
  1036  	ValueTypeF32 = api.ValueTypeF32
  1037  	ValueTypeF64 = api.ValueTypeF64
  1038  	// TODO: ValueTypeV128 is not exposed in the api pkg yet.
  1039  	ValueTypeV128 ValueType = 0x7b
  1040  	// TODO: ValueTypeFuncref is not exposed in the api pkg yet.
  1041  	ValueTypeFuncref   ValueType = 0x70
  1042  	ValueTypeExternref           = api.ValueTypeExternref
  1043  )
  1044  
  1045  // ValueTypeName is an alias of api.ValueTypeName defined to simplify imports.
  1046  func ValueTypeName(t ValueType) string {
  1047  	if t == ValueTypeFuncref {
  1048  		return "funcref"
  1049  	} else if t == ValueTypeV128 {
  1050  		return "v128"
  1051  	}
  1052  	return api.ValueTypeName(t)
  1053  }
  1054  
  1055  func isReferenceValueType(vt ValueType) bool {
  1056  	return vt == ValueTypeExternref || vt == ValueTypeFuncref
  1057  }
  1058  
  1059  // ExternType is an alias of api.ExternType defined to simplify imports.
  1060  type ExternType = api.ExternType
  1061  
  1062  const (
  1063  	ExternTypeFunc       = api.ExternTypeFunc
  1064  	ExternTypeFuncName   = api.ExternTypeFuncName
  1065  	ExternTypeTable      = api.ExternTypeTable
  1066  	ExternTypeTableName  = api.ExternTypeTableName
  1067  	ExternTypeMemory     = api.ExternTypeMemory
  1068  	ExternTypeMemoryName = api.ExternTypeMemoryName
  1069  	ExternTypeGlobal     = api.ExternTypeGlobal
  1070  	ExternTypeGlobalName = api.ExternTypeGlobalName
  1071  )
  1072  
  1073  // ExternTypeName is an alias of api.ExternTypeName defined to simplify imports.
  1074  func ExternTypeName(t ValueType) string {
  1075  	return api.ExternTypeName(t)
  1076  }