github.com/tetratelabs/wazero@v1.2.1/internal/wasm/module.go (about)

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