github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/wasm/table_test.go (about)

     1  package wasm
     2  
     3  import (
     4  	"math"
     5  	"testing"
     6  
     7  	"github.com/tetratelabs/wazero/api"
     8  	"github.com/tetratelabs/wazero/internal/leb128"
     9  	"github.com/tetratelabs/wazero/internal/testing/require"
    10  )
    11  
    12  // Test_ElementInitNullReference_valid ensures it is actually safe to use ElementInitNullReference
    13  // as a null reference, and it won't collide with the actual function Index.
    14  func Test_ElementInitNullReference_valid(t *testing.T) {
    15  	require.True(t, MaximumFunctionIndex < ElementInitNullReference)
    16  }
    17  
    18  func Test_resolveImports_table(t *testing.T) {
    19  	const moduleName = "test"
    20  	const name = "target"
    21  
    22  	t.Run("ok", func(t *testing.T) {
    23  		max := uint32(10)
    24  		tableInst := &TableInstance{Max: &max, involvingModuleInstances: []*ModuleInstance{{}}}
    25  		s := newStore()
    26  		s.nameToModule[moduleName] = &ModuleInstance{
    27  			Tables:     []*TableInstance{tableInst},
    28  			Exports:    map[string]*Export{name: {Type: ExternTypeTable, Index: 0}},
    29  			ModuleName: moduleName,
    30  		}
    31  		m := &ModuleInstance{Tables: make([]*TableInstance, 1), s: s}
    32  		err := m.resolveImports(&Module{
    33  			ImportPerModule: map[string][]*Import{
    34  				moduleName: {{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: Table{Max: &max}}},
    35  			},
    36  		})
    37  		require.NoError(t, err)
    38  		require.Equal(t, m.Tables[0], tableInst)
    39  		require.Equal(t, m.Tables[0].involvingModuleInstances[1], m)
    40  	})
    41  	t.Run("minimum size mismatch", func(t *testing.T) {
    42  		s := newStore()
    43  		importTableType := Table{Min: 2}
    44  		s.nameToModule[moduleName] = &ModuleInstance{
    45  			Tables:     []*TableInstance{{Min: importTableType.Min - 1}},
    46  			Exports:    map[string]*Export{name: {Type: ExternTypeTable}},
    47  			ModuleName: moduleName,
    48  		}
    49  		m := &ModuleInstance{Tables: make([]*TableInstance, 1), s: s}
    50  		err := m.resolveImports(&Module{
    51  			ImportPerModule: map[string][]*Import{
    52  				moduleName: {{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: importTableType}},
    53  			},
    54  		})
    55  		require.EqualError(t, err, "import table[test.target]: minimum size mismatch: 2 > 1")
    56  	})
    57  	t.Run("maximum size mismatch", func(t *testing.T) {
    58  		max := uint32(10)
    59  		importTableType := Table{Max: &max}
    60  		s := newStore()
    61  		s.nameToModule[moduleName] = &ModuleInstance{
    62  			Tables:     []*TableInstance{{Min: importTableType.Min - 1}},
    63  			Exports:    map[string]*Export{name: {Type: ExternTypeTable}},
    64  			ModuleName: moduleName,
    65  		}
    66  		m := &ModuleInstance{Tables: make([]*TableInstance, 1), s: s}
    67  		err := m.resolveImports(&Module{
    68  			ImportPerModule: map[string][]*Import{
    69  				moduleName: {{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: importTableType}},
    70  			},
    71  		})
    72  		require.EqualError(t, err, "import table[test.target]: maximum size mismatch: 10, but actual has no max")
    73  	})
    74  	t.Run("type mismatch", func(t *testing.T) {
    75  		s := newStore()
    76  		s.nameToModule[moduleName] = &ModuleInstance{
    77  			Tables:     []*TableInstance{{Type: RefTypeFuncref}},
    78  			Exports:    map[string]*Export{name: {Type: ExternTypeTable}},
    79  			ModuleName: moduleName,
    80  		}
    81  		m := &ModuleInstance{Tables: make([]*TableInstance, 1), s: s}
    82  		err := m.resolveImports(&Module{
    83  			ImportPerModule: map[string][]*Import{
    84  				moduleName: {{Module: moduleName, Name: name, Type: ExternTypeTable, DescTable: Table{Type: RefTypeExternref}}},
    85  			},
    86  		})
    87  		require.EqualError(t, err, "import table[test.target]: table type mismatch: externref != funcref")
    88  	})
    89  }
    90  
    91  var codeEnd = Code{Body: []byte{OpcodeEnd}}
    92  
    93  func TestModule_validateTable(t *testing.T) {
    94  	const maxTableIndex = 5
    95  	three := uint32(3)
    96  	tests := []struct {
    97  		name  string
    98  		input *Module
    99  	}{
   100  		{
   101  			name:  "empty",
   102  			input: &Module{},
   103  		},
   104  		{
   105  			name:  "min zero",
   106  			input: &Module{TableSection: []Table{{}}},
   107  		},
   108  		{
   109  			name:  "maximum number of tables",
   110  			input: &Module{TableSection: []Table{{}, {}, {}, {}, {}}},
   111  		},
   112  		{
   113  			name:  "min/max",
   114  			input: &Module{TableSection: []Table{{Min: 1, Max: &three}}},
   115  		},
   116  		{ // See: https://github.com/WebAssembly/spec/issues/1427
   117  			name: "constant derived element offset=0 and no index",
   118  			input: &Module{
   119  				TypeSection:     []FunctionType{{}},
   120  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   121  				FunctionSection: []Index{0},
   122  				CodeSection:     []Code{codeEnd},
   123  				ElementSection: []ElementSegment{
   124  					{
   125  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const0},
   126  						Type:       RefTypeFuncref,
   127  					},
   128  				},
   129  			},
   130  		},
   131  		{
   132  			name: "constant derived element offset=0 and one index",
   133  			input: &Module{
   134  				TypeSection:     []FunctionType{{}},
   135  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   136  				FunctionSection: []Index{0},
   137  				CodeSection:     []Code{codeEnd},
   138  				ElementSection: []ElementSegment{
   139  					{
   140  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const0},
   141  						Init:       []Index{0},
   142  						Type:       RefTypeFuncref,
   143  					},
   144  				},
   145  			},
   146  		},
   147  		{
   148  			name: "constant derived element offset - ignores min on imported table",
   149  			input: &Module{
   150  				ImportTableCount: 1,
   151  				TypeSection:      []FunctionType{{}},
   152  				ImportSection:    []Import{{Type: ExternTypeTable, DescTable: Table{Type: RefTypeFuncref}}},
   153  				FunctionSection:  []Index{0},
   154  				CodeSection:      []Code{codeEnd},
   155  				ElementSection: []ElementSegment{
   156  					{
   157  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const0},
   158  						Init:       []Index{0},
   159  						Type:       RefTypeFuncref,
   160  					},
   161  				},
   162  			},
   163  		},
   164  		{
   165  			name: "constant derived element offset=0 and one index - imported table",
   166  			input: &Module{
   167  				TypeSection:     []FunctionType{{}},
   168  				ImportSection:   []Import{{Type: ExternTypeTable, DescTable: Table{Min: 1, Type: RefTypeFuncref}}},
   169  				FunctionSection: []Index{0},
   170  				CodeSection:     []Code{codeEnd},
   171  				ElementSection: []ElementSegment{
   172  					{
   173  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const0},
   174  						Init:       []Index{0},
   175  						Type:       RefTypeFuncref,
   176  					},
   177  				},
   178  			},
   179  		},
   180  		{
   181  			name: "constant derived element offset and two indices",
   182  			input: &Module{
   183  				TypeSection:     []FunctionType{{}},
   184  				TableSection:    []Table{{Min: 3, Type: RefTypeFuncref}},
   185  				FunctionSection: []Index{0, 0, 0, 0},
   186  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   187  				ElementSection: []ElementSegment{
   188  					{
   189  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
   190  						Init:       []Index{0, 2},
   191  						Type:       RefTypeFuncref,
   192  					},
   193  				},
   194  			},
   195  		},
   196  		{ // See: https://github.com/WebAssembly/spec/issues/1427
   197  			name: "imported global derived element offset and no index",
   198  			input: &Module{
   199  				TypeSection: []FunctionType{{}},
   200  				ImportSection: []Import{
   201  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   202  				},
   203  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   204  				FunctionSection: []Index{0},
   205  				CodeSection:     []Code{codeEnd},
   206  				ElementSection: []ElementSegment{
   207  					{
   208  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
   209  						Type:       RefTypeFuncref,
   210  					},
   211  				},
   212  			},
   213  		},
   214  		{
   215  			name: "imported global derived element offset and one index",
   216  			input: &Module{
   217  				TypeSection: []FunctionType{{}},
   218  				ImportSection: []Import{
   219  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   220  				},
   221  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   222  				FunctionSection: []Index{0},
   223  				CodeSection:     []Code{codeEnd},
   224  				ElementSection: []ElementSegment{
   225  					{
   226  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
   227  						Init:       []Index{0},
   228  						Type:       RefTypeFuncref,
   229  					},
   230  				},
   231  			},
   232  		},
   233  		{
   234  			name: "imported global derived element offset and one index - imported table",
   235  			input: &Module{
   236  				TypeSection: []FunctionType{{}},
   237  				ImportSection: []Import{
   238  					{Type: ExternTypeTable, DescTable: Table{Min: 1, Type: RefTypeFuncref}},
   239  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   240  				},
   241  				FunctionSection: []Index{0},
   242  				CodeSection:     []Code{codeEnd},
   243  				ElementSection: []ElementSegment{
   244  					{
   245  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
   246  						Init:       []Index{0},
   247  						Type:       RefTypeFuncref,
   248  					},
   249  				},
   250  			},
   251  		},
   252  		{
   253  			name: "imported global derived element offset - ignores min on imported table",
   254  			input: &Module{
   255  				TypeSection: []FunctionType{{}},
   256  				ImportSection: []Import{
   257  					{Type: ExternTypeTable, DescTable: Table{Type: RefTypeFuncref}},
   258  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   259  				},
   260  				FunctionSection: []Index{0},
   261  				CodeSection:     []Code{codeEnd},
   262  				ElementSection: []ElementSegment{
   263  					{
   264  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
   265  						Init:       []Index{0},
   266  						Type:       RefTypeFuncref,
   267  					},
   268  				},
   269  			},
   270  		},
   271  		{
   272  			name: "imported global derived element offset - two indices",
   273  			input: &Module{
   274  				TypeSection: []FunctionType{{}},
   275  				ImportSection: []Import{
   276  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI64}},
   277  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   278  				},
   279  				TableSection:    []Table{{Min: 3, Type: RefTypeFuncref}},
   280  				FunctionSection: []Index{0, 0, 0, 0},
   281  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   282  				ElementSection: []ElementSegment{
   283  					{
   284  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x1}},
   285  						Init:       []Index{0, 2},
   286  						Type:       RefTypeFuncref,
   287  					},
   288  				},
   289  			},
   290  		},
   291  		{
   292  			name: "constant offset - two inits from globals - funcref",
   293  			input: &Module{
   294  				TypeSection: []FunctionType{{}},
   295  				ImportSection: []Import{
   296  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeFuncref}},
   297  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeFuncref}},
   298  				},
   299  				ImportGlobalCount: 2,
   300  				TableSection:      []Table{{Min: 10, Type: RefTypeFuncref}},
   301  				ElementSection: []ElementSegment{
   302  					{
   303  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0x5}},
   304  						Init:       []Index{WrapGlobalIndexAsElementInit(0), WrapGlobalIndexAsElementInit(1)},
   305  						Type:       RefTypeFuncref,
   306  					},
   307  				},
   308  			},
   309  		},
   310  		{
   311  			name: "constant offset - two inits from globals - externref",
   312  			input: &Module{
   313  				TypeSection: []FunctionType{{}},
   314  				ImportSection: []Import{
   315  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeExternref}},
   316  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeExternref}},
   317  				},
   318  				ImportGlobalCount: 2,
   319  				TableSection:      []Table{{Min: 10, Type: RefTypeExternref}},
   320  				ElementSection: []ElementSegment{
   321  					{
   322  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0x5}},
   323  						Init:       []Index{elementInitImportedGlobalReferenceType, elementInitImportedGlobalReferenceType | 1},
   324  						Type:       RefTypeExternref,
   325  					},
   326  				},
   327  			},
   328  		},
   329  		{
   330  			name: "mixed elementSegments - const before imported global",
   331  			input: &Module{
   332  				TypeSection: []FunctionType{{}},
   333  				ImportSection: []Import{
   334  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI64}},
   335  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   336  				},
   337  				TableSection:    []Table{{Min: 3, Type: RefTypeFuncref}},
   338  				FunctionSection: []Index{0, 0, 0, 0},
   339  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   340  				ElementSection: []ElementSegment{
   341  					{
   342  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
   343  						Init:       []Index{0, 2},
   344  						Type:       RefTypeFuncref,
   345  					},
   346  					{
   347  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x1}},
   348  						Init:       []Index{1, 2},
   349  						Type:       RefTypeFuncref,
   350  					},
   351  				},
   352  			},
   353  		},
   354  	}
   355  
   356  	for _, tt := range tests {
   357  		tc := tt
   358  
   359  		t.Run(tc.name, func(t *testing.T) {
   360  			_, _, _, tables, err := tc.input.AllDeclarations()
   361  			require.NoError(t, err)
   362  
   363  			err = tc.input.validateTable(api.CoreFeaturesV1, tables, maxTableIndex)
   364  			require.NoError(t, err)
   365  
   366  			err = tc.input.validateTable(api.CoreFeaturesV1, tables, maxTableIndex)
   367  			require.NoError(t, err)
   368  		})
   369  	}
   370  }
   371  
   372  func TestModule_validateTable_Errors(t *testing.T) {
   373  	const maxTableIndex = 5
   374  	tests := []struct {
   375  		name        string
   376  		input       *Module
   377  		expectedErr string
   378  	}{
   379  		{
   380  			name: "too many tables",
   381  			input: &Module{
   382  				TableSection: []Table{{}, {}, {}, {}, {}, {}},
   383  			},
   384  			expectedErr: "too many tables in a module: 6 given with limit 5",
   385  		},
   386  		{
   387  			name: "type mismatch: unknown ref type",
   388  			input: &Module{
   389  				TableSection: []Table{{Type: RefTypeFuncref}},
   390  				ElementSection: []ElementSegment{
   391  					{
   392  						OffsetExpr: ConstantExpression{
   393  							Opcode: OpcodeI32Const,
   394  							Data:   leb128.EncodeUint64(math.MaxUint64),
   395  						},
   396  						Type: 0xff,
   397  					},
   398  				},
   399  			},
   400  			expectedErr: "element type mismatch: table has funcref but element has unknown(0xff)",
   401  		},
   402  		{
   403  			name: "type mismatch: funcref elem on extern table",
   404  			input: &Module{
   405  				TableSection: []Table{{Type: RefTypeExternref}},
   406  				ElementSection: []ElementSegment{
   407  					{
   408  						OffsetExpr: ConstantExpression{
   409  							Opcode: OpcodeI32Const,
   410  							Data:   leb128.EncodeUint64(math.MaxUint64),
   411  						},
   412  						Type: RefTypeFuncref,
   413  					},
   414  				},
   415  			},
   416  			expectedErr: "element type mismatch: table has externref but element has funcref",
   417  		},
   418  		{
   419  			name: "type mismatch: extern elem on funcref table",
   420  			input: &Module{
   421  				TableSection: []Table{{Type: RefTypeFuncref}},
   422  				ElementSection: []ElementSegment{
   423  					{
   424  						OffsetExpr: ConstantExpression{
   425  							Opcode: OpcodeI32Const,
   426  							Data:   leb128.EncodeUint64(math.MaxUint64),
   427  						},
   428  						Type: RefTypeExternref,
   429  					},
   430  				},
   431  			},
   432  			expectedErr: "element type mismatch: table has funcref but element has externref",
   433  		},
   434  		{
   435  			name: "non-nil non-global externref",
   436  			input: &Module{
   437  				TableSection: []Table{{Type: RefTypeFuncref}},
   438  				ElementSection: []ElementSegment{
   439  					{
   440  						OffsetExpr: ConstantExpression{
   441  							Opcode: OpcodeI32Const,
   442  							Data:   leb128.EncodeUint64(math.MaxUint64),
   443  						},
   444  						Type: RefTypeExternref,
   445  						Init: []Index{0},
   446  					},
   447  				},
   448  			},
   449  			expectedErr: "element[0].init[0] must be ref.null but was 0",
   450  		},
   451  		{
   452  			name: "constant derived element offset - decode error",
   453  			input: &Module{
   454  				TypeSection:     []FunctionType{{}},
   455  				TableSection:    []Table{{Type: RefTypeFuncref}},
   456  				FunctionSection: []Index{0},
   457  				CodeSection:     []Code{codeEnd},
   458  				ElementSection: []ElementSegment{
   459  					{
   460  						OffsetExpr: ConstantExpression{
   461  							Opcode: OpcodeI32Const,
   462  							Data:   leb128.EncodeUint64(math.MaxUint64),
   463  						},
   464  						Init: []Index{0},
   465  						Type: RefTypeFuncref,
   466  					},
   467  				},
   468  			},
   469  			expectedErr: "element[0] couldn't read i32.const parameter: overflows a 32-bit integer",
   470  		},
   471  		{
   472  			name: "constant derived element offset - wrong ValType",
   473  			input: &Module{
   474  				TypeSection:     []FunctionType{{}},
   475  				TableSection:    []Table{{Type: RefTypeFuncref}},
   476  				FunctionSection: []Index{0},
   477  				CodeSection:     []Code{codeEnd},
   478  				ElementSection: []ElementSegment{
   479  					{
   480  						OffsetExpr: ConstantExpression{Opcode: OpcodeI64Const, Data: const0}, Init: []Index{0},
   481  						Type: RefTypeFuncref,
   482  					},
   483  				},
   484  			},
   485  			expectedErr: "element[0] has an invalid const expression: i64.const",
   486  		},
   487  		{
   488  			name: "constant derived element offset - missing table",
   489  			input: &Module{
   490  				TypeSection:     []FunctionType{{}},
   491  				FunctionSection: []Index{0},
   492  				CodeSection:     []Code{codeEnd},
   493  				ElementSection: []ElementSegment{
   494  					{
   495  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const0}, Init: []Index{0},
   496  						Type: RefTypeFuncref,
   497  					},
   498  				},
   499  			},
   500  			expectedErr: "unknown table 0 as active element target",
   501  		},
   502  		{
   503  			name: "constant derived element offset exceeds table min",
   504  			input: &Module{
   505  				TypeSection:     []FunctionType{{}},
   506  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   507  				FunctionSection: []Index{0},
   508  				CodeSection:     []Code{codeEnd},
   509  				ElementSection: []ElementSegment{
   510  					{
   511  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(2)}, Init: []Index{0},
   512  						Type: RefTypeFuncref,
   513  					},
   514  				},
   515  			},
   516  			expectedErr: "element[0].init exceeds min table size",
   517  		},
   518  		{
   519  			name: "constant derived element offset puts init beyond table min",
   520  			input: &Module{
   521  				TypeSection:     []FunctionType{{}},
   522  				TableSection:    []Table{{Min: 2, Type: RefTypeFuncref}},
   523  				FunctionSection: []Index{0},
   524  				CodeSection:     []Code{codeEnd},
   525  				ElementSection: []ElementSegment{
   526  					{
   527  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, Init: []Index{0},
   528  						Type: RefTypeFuncref,
   529  					},
   530  					{
   531  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, Init: []Index{0, 0},
   532  						Type: RefTypeFuncref,
   533  					},
   534  				},
   535  			},
   536  			expectedErr: "element[1].init exceeds min table size",
   537  		},
   538  		{ // See: https://github.com/WebAssembly/spec/issues/1427
   539  			name: "constant derived element offset beyond table min - no init elements",
   540  			input: &Module{
   541  				TypeSection:     []FunctionType{{}},
   542  				TableSection:    []Table{{Min: 1, Type: RefTypeFuncref}},
   543  				FunctionSection: []Index{0},
   544  				CodeSection:     []Code{codeEnd},
   545  				ElementSection: []ElementSegment{
   546  					{
   547  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(2)},
   548  						Type:       RefTypeFuncref,
   549  					},
   550  				},
   551  			},
   552  			expectedErr: "element[0].init exceeds min table size",
   553  		},
   554  		{
   555  			name: "constant derived element offset - func index out of range",
   556  			input: &Module{
   557  				TypeSection:     []FunctionType{{}},
   558  				TableSection:    []Table{{Min: 1}},
   559  				FunctionSection: []Index{0},
   560  				CodeSection:     []Code{codeEnd},
   561  				ElementSection: []ElementSegment{
   562  					{
   563  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, Init: []Index{0, 1},
   564  						Type: RefTypeFuncref,
   565  					},
   566  				},
   567  			},
   568  			expectedErr: "element[0].init[1] func index 1 out of range",
   569  		},
   570  		{
   571  			name: "constant derived element offset - global out of range",
   572  			input: &Module{
   573  				ImportGlobalCount: 50,
   574  				TypeSection:       []FunctionType{{}},
   575  				TableSection:      []Table{{Min: 1}},
   576  				FunctionSection:   []Index{0},
   577  				CodeSection:       []Code{codeEnd},
   578  				ElementSection: []ElementSegment{
   579  					{
   580  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, Init: []Index{
   581  							elementInitImportedGlobalReferenceType | 1,
   582  							elementInitImportedGlobalReferenceType | 100,
   583  						},
   584  						Type: RefTypeFuncref,
   585  					},
   586  				},
   587  			},
   588  			expectedErr: "element[0].init[1] global index 100 out of range",
   589  		},
   590  		{
   591  			name: "imported global derived element offset - missing table",
   592  			input: &Module{
   593  				TypeSection: []FunctionType{{}},
   594  				ImportSection: []Import{
   595  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   596  				},
   597  				FunctionSection: []Index{0},
   598  				CodeSection:     []Code{codeEnd},
   599  				ElementSection: []ElementSegment{
   600  					{
   601  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}}, Init: []Index{0},
   602  						Type: RefTypeFuncref,
   603  					},
   604  				},
   605  			},
   606  			expectedErr: "unknown table 0 as active element target",
   607  		},
   608  		{
   609  			name: "imported global derived element offset - func index out of range",
   610  			input: &Module{
   611  				TypeSection: []FunctionType{{}},
   612  				ImportSection: []Import{
   613  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   614  				},
   615  				TableSection:    []Table{{Min: 1}},
   616  				FunctionSection: []Index{0},
   617  				CodeSection:     []Code{codeEnd},
   618  				ElementSection: []ElementSegment{
   619  					{
   620  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}}, Init: []Index{0, 1},
   621  						Type: RefTypeFuncref,
   622  					},
   623  				},
   624  			},
   625  			expectedErr: "element[0].init[1] func index 1 out of range",
   626  		},
   627  		{
   628  			name: "imported global derived element offset - wrong ValType",
   629  			input: &Module{
   630  				TypeSection: []FunctionType{{}},
   631  				ImportSection: []Import{
   632  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI64}},
   633  				},
   634  				TableSection:    []Table{{Type: RefTypeFuncref}},
   635  				FunctionSection: []Index{0},
   636  				CodeSection:     []Code{codeEnd},
   637  				ElementSection: []ElementSegment{
   638  					{
   639  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}}, Init: []Index{0},
   640  						Type: RefTypeFuncref,
   641  					},
   642  				},
   643  			},
   644  			expectedErr: "element[0] (global.get 0): import[0].global.ValType != i32",
   645  		},
   646  		{
   647  			name: "imported global derived element offset - decode error",
   648  			input: &Module{
   649  				TypeSection: []FunctionType{{}},
   650  				ImportSection: []Import{
   651  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   652  				},
   653  				TableSection:    []Table{{Type: RefTypeFuncref}},
   654  				FunctionSection: []Index{0},
   655  				CodeSection:     []Code{codeEnd},
   656  				ElementSection: []ElementSegment{
   657  					{
   658  						OffsetExpr: ConstantExpression{
   659  							Opcode: OpcodeGlobalGet,
   660  							Data:   leb128.EncodeUint64(math.MaxUint64),
   661  						},
   662  						Init: []Index{0},
   663  						Type: RefTypeFuncref,
   664  					},
   665  				},
   666  			},
   667  			expectedErr: "element[0] couldn't read global.get parameter: overflows a 32-bit integer",
   668  		},
   669  		{
   670  			name: "imported global derived element offset - no imports",
   671  			input: &Module{
   672  				TypeSection:     []FunctionType{{}},
   673  				TableSection:    []Table{{Type: RefTypeFuncref}},
   674  				FunctionSection: []Index{0},
   675  				GlobalSection:   []Global{{Type: GlobalType{ValType: ValueTypeI32}}}, // ignored as not imported
   676  				CodeSection:     []Code{codeEnd},
   677  				ElementSection: []ElementSegment{
   678  					{
   679  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}}, Init: []Index{0},
   680  						Type: RefTypeFuncref,
   681  					},
   682  				},
   683  			},
   684  			expectedErr: "element[0] (global.get 0): out of range of imported globals",
   685  		},
   686  		{
   687  			name: "imported global derived element offset - no imports are globals",
   688  			input: &Module{
   689  				TypeSection: []FunctionType{{}},
   690  				ImportSection: []Import{
   691  					{Type: ExternTypeFunc, DescFunc: 0},
   692  				},
   693  				TableSection:    []Table{{Type: RefTypeFuncref}},
   694  				FunctionSection: []Index{0},
   695  				GlobalSection:   []Global{{Type: GlobalType{ValType: ValueTypeI32}}}, // ignored as not imported
   696  				CodeSection:     []Code{codeEnd},
   697  				ElementSection: []ElementSegment{
   698  					{
   699  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}}, Init: []Index{0},
   700  						Type: RefTypeFuncref,
   701  					},
   702  				},
   703  			},
   704  			expectedErr: "element[0] (global.get 0): out of range of imported globals",
   705  		},
   706  	}
   707  
   708  	for _, tt := range tests {
   709  		tc := tt
   710  
   711  		t.Run(tc.name, func(t *testing.T) {
   712  			_, _, _, tables, err := tc.input.AllDeclarations()
   713  			require.NoError(t, err)
   714  			err = tc.input.validateTable(api.CoreFeaturesV1, tables, maxTableIndex)
   715  			require.EqualError(t, err, tc.expectedErr)
   716  		})
   717  	}
   718  }
   719  
   720  var (
   721  	const0 = leb128.EncodeInt32(0)
   722  	const1 = leb128.EncodeInt32(1)
   723  )
   724  
   725  func TestModule_buildTables(t *testing.T) {
   726  	three := uint32(3)
   727  	tests := []struct {
   728  		name            string
   729  		module          *Module
   730  		importedTables  []*TableInstance
   731  		importedGlobals []*GlobalInstance
   732  		expectedTables  []*TableInstance
   733  	}{
   734  		{
   735  			name: "empty",
   736  			module: &Module{
   737  				ElementSection: []ElementSegment{},
   738  			},
   739  		},
   740  		{
   741  			name: "min zero",
   742  			module: &Module{
   743  				TableSection:   []Table{{Type: RefTypeFuncref}},
   744  				ElementSection: []ElementSegment{},
   745  			},
   746  			expectedTables: []*TableInstance{{References: make([]Reference, 0), Min: 0, Type: RefTypeFuncref}},
   747  		},
   748  		{
   749  			name: "min/max",
   750  			module: &Module{
   751  				TableSection:   []Table{{Min: 1, Max: &three}},
   752  				ElementSection: []ElementSegment{},
   753  			},
   754  			expectedTables: []*TableInstance{{References: make([]Reference, 1), Min: 1, Max: &three}},
   755  		},
   756  		{ // See: https://github.com/WebAssembly/spec/issues/1427
   757  			name: "constant derived element offset=0 and no index",
   758  			module: &Module{
   759  				TypeSection:     []FunctionType{{}},
   760  				TableSection:    []Table{{Min: 1}},
   761  				FunctionSection: []Index{0},
   762  				CodeSection:     []Code{codeEnd},
   763  				ElementSection:  []ElementSegment{},
   764  			},
   765  			expectedTables: []*TableInstance{{References: make([]Reference, 1), Min: 1}},
   766  		},
   767  		{
   768  			name: "null extern refs",
   769  			module: &Module{
   770  				TableSection: []Table{{Min: 10, Type: RefTypeExternref}},
   771  				ElementSection: []ElementSegment{
   772  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{5}}, Init: []Index{ElementInitNullReference, ElementInitNullReference, ElementInitNullReference}}, // three null refs.
   773  				},
   774  			},
   775  			expectedTables: []*TableInstance{{References: make([]Reference, 10), Min: 10, Type: RefTypeExternref}},
   776  		},
   777  		{
   778  			name: "constant derived element offset=0 and one index",
   779  			module: &Module{
   780  				TypeSection:     []FunctionType{{}},
   781  				TableSection:    []Table{{Min: 1}},
   782  				FunctionSection: []Index{0},
   783  				CodeSection:     []Code{codeEnd},
   784  				ElementSection: []ElementSegment{
   785  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   786  				},
   787  			},
   788  			expectedTables: []*TableInstance{{References: make([]Reference, 1), Min: 1}},
   789  		},
   790  		{
   791  			name: "constant derived element offset - imported table",
   792  			module: &Module{
   793  				TypeSection:     []FunctionType{{}},
   794  				FunctionSection: []Index{0},
   795  				CodeSection:     []Code{codeEnd},
   796  				ElementSection: []ElementSegment{
   797  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   798  				},
   799  			},
   800  			importedTables: []*TableInstance{{Min: 2}},
   801  			expectedTables: []*TableInstance{{Min: 2}},
   802  		},
   803  		{
   804  			name: "constant derived element offset=0 and one index - imported table",
   805  			module: &Module{
   806  				TypeSection:     []FunctionType{{}},
   807  				ImportSection:   []Import{{Type: ExternTypeTable, DescTable: Table{Min: 1}}},
   808  				FunctionSection: []Index{0},
   809  				CodeSection:     []Code{codeEnd},
   810  				ElementSection: []ElementSegment{
   811  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   812  				},
   813  			},
   814  			importedTables: []*TableInstance{{Min: 1}},
   815  			expectedTables: []*TableInstance{{Min: 1}},
   816  		},
   817  		{
   818  			name: "constant derived element offset and two indices",
   819  			module: &Module{
   820  				TypeSection:     []FunctionType{{}},
   821  				TableSection:    []Table{{Min: 3}},
   822  				FunctionSection: []Index{0, 0, 0, 0},
   823  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   824  				ElementSection: []ElementSegment{
   825  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{1}}, Init: []Index{0, 2}},
   826  				},
   827  			},
   828  			expectedTables: []*TableInstance{{References: make([]Reference, 3), Min: 3}},
   829  		},
   830  		{ // See: https://github.com/WebAssembly/spec/issues/1427
   831  			name: "imported global derived element offset and no index",
   832  			module: &Module{
   833  				TypeSection: []FunctionType{{}},
   834  				ImportSection: []Import{
   835  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   836  				},
   837  				TableSection:    []Table{{Min: 1}},
   838  				FunctionSection: []Index{0},
   839  				CodeSection:     []Code{codeEnd},
   840  				ElementSection:  []ElementSegment{},
   841  			},
   842  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 1}},
   843  			expectedTables:  []*TableInstance{{References: make([]Reference, 1), Min: 1}},
   844  		},
   845  		{
   846  			name: "imported global derived element offset and one index",
   847  			module: &Module{
   848  				TypeSection: []FunctionType{{}},
   849  				ImportSection: []Import{
   850  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   851  				},
   852  				TableSection:    []Table{{Min: 2}},
   853  				FunctionSection: []Index{0},
   854  				CodeSection:     []Code{codeEnd},
   855  				ElementSection: []ElementSegment{
   856  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   857  				},
   858  			},
   859  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 1}},
   860  			expectedTables:  []*TableInstance{{References: make([]Reference, 2), Min: 2}},
   861  		},
   862  		{
   863  			name: "imported global derived element offset and one index - imported table",
   864  			module: &Module{
   865  				TypeSection: []FunctionType{{}},
   866  				ImportSection: []Import{
   867  					{Type: ExternTypeTable, DescTable: Table{Min: 1}},
   868  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   869  				},
   870  				FunctionSection: []Index{0},
   871  				CodeSection:     []Code{codeEnd},
   872  				ElementSection: []ElementSegment{
   873  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   874  				},
   875  			},
   876  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 1}},
   877  			importedTables:  []*TableInstance{{References: make([]Reference, 2), Min: 2}},
   878  			expectedTables:  []*TableInstance{{Min: 2, References: []Reference{0, 0}}},
   879  		},
   880  		{
   881  			name: "imported global derived element offset - ignores min on imported table",
   882  			module: &Module{
   883  				TypeSection: []FunctionType{{}},
   884  				ImportSection: []Import{
   885  					{Type: ExternTypeTable, DescTable: Table{}},
   886  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   887  				},
   888  				FunctionSection: []Index{0},
   889  				CodeSection:     []Code{codeEnd},
   890  				ElementSection: []ElementSegment{
   891  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{0}}, Init: []Index{0}},
   892  				},
   893  			},
   894  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 1}},
   895  			importedTables:  []*TableInstance{{References: make([]Reference, 2), Min: 2}},
   896  			expectedTables:  []*TableInstance{{Min: 2, References: []Reference{0, 0}}},
   897  		},
   898  		{
   899  			name: "imported global derived element offset - two indices",
   900  			module: &Module{
   901  				TypeSection: []FunctionType{{}},
   902  				ImportSection: []Import{
   903  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI64}},
   904  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   905  				},
   906  				TableSection:    []Table{{Min: 3}, {Min: 100}},
   907  				FunctionSection: []Index{0, 0, 0, 0},
   908  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   909  				ElementSection: []ElementSegment{
   910  					{
   911  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
   912  						Init:       []Index{ElementInitNullReference, 2},
   913  						TableIndex: 1,
   914  					},
   915  					{
   916  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x1}},
   917  						Init:       []Index{0, 2},
   918  						TableIndex: 0,
   919  					},
   920  				},
   921  			},
   922  			importedGlobals: []*GlobalInstance{
   923  				{Type: GlobalType{ValType: ValueTypeI64}, Val: 3},
   924  				{Type: GlobalType{ValType: ValueTypeI32}, Val: 1},
   925  			},
   926  			expectedTables: []*TableInstance{
   927  				{References: make([]Reference, 3), Min: 3},
   928  				{References: make([]Reference, 100), Min: 100},
   929  			},
   930  		},
   931  		{
   932  			name: "mixed elementSegments - const before imported global",
   933  			module: &Module{
   934  				TypeSection: []FunctionType{{}},
   935  				ImportSection: []Import{
   936  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI64}},
   937  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
   938  				},
   939  				TableSection:    []Table{{Min: 3}},
   940  				FunctionSection: []Index{0, 0, 0, 0},
   941  				CodeSection:     []Code{codeEnd, codeEnd, codeEnd, codeEnd},
   942  				ElementSection: []ElementSegment{
   943  					{OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{1}}, Init: []Index{0, 2}},
   944  					{OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{1}}, Init: []Index{1, 2}},
   945  				},
   946  			},
   947  			importedGlobals: []*GlobalInstance{
   948  				{Type: GlobalType{ValType: ValueTypeI64}, Val: 3},
   949  				{Type: GlobalType{ValType: ValueTypeI32}, Val: 1},
   950  			},
   951  			expectedTables: []*TableInstance{{References: make([]Reference, 3), Min: 3}},
   952  		},
   953  	}
   954  
   955  	for _, tt := range tests {
   956  		tc := tt
   957  
   958  		t.Run(tc.name, func(t *testing.T) {
   959  			m := &ModuleInstance{
   960  				Tables:  append(tc.importedTables, make([]*TableInstance, len(tc.module.TableSection))...),
   961  				Globals: tc.importedGlobals,
   962  			}
   963  			err := m.buildTables(tc.module, false)
   964  			require.NoError(t, err)
   965  
   966  			require.Equal(t, tc.expectedTables, m.Tables)
   967  		})
   968  	}
   969  }
   970  
   971  // TestModule_buildTable_Errors covers the only late error conditions possible.
   972  func TestModule_buildTable_Errors(t *testing.T) {
   973  	tests := []struct {
   974  		name            string
   975  		module          *Module
   976  		importedTables  []*TableInstance
   977  		importedGlobals []*GlobalInstance
   978  		expectedErr     string
   979  	}{
   980  		{
   981  			name: "constant derived element offset exceeds table min - imported table",
   982  			module: &Module{
   983  				TypeSection:     []FunctionType{{}},
   984  				ImportSection:   []Import{{Type: ExternTypeTable, DescTable: Table{}}},
   985  				FunctionSection: []Index{0},
   986  				CodeSection:     []Code{codeEnd},
   987  				ElementSection: []ElementSegment{
   988  					{
   989  						OffsetExpr: ConstantExpression{Opcode: OpcodeI32Const, Data: []byte{2}},
   990  						Init:       []Index{0},
   991  					},
   992  				},
   993  			},
   994  			importedTables: []*TableInstance{{References: make([]Reference, 2), Min: 2}},
   995  			expectedErr:    "element[0].init exceeds min table size",
   996  		},
   997  		{
   998  			name: "imported global derived element offset exceeds table min",
   999  			module: &Module{
  1000  				TypeSection: []FunctionType{{}},
  1001  				ImportSection: []Import{
  1002  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
  1003  				},
  1004  				TableSection:    []Table{{Min: 2}},
  1005  				FunctionSection: []Index{0},
  1006  				CodeSection:     []Code{codeEnd},
  1007  				ElementSection: []ElementSegment{
  1008  					{
  1009  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
  1010  						Init:       []Index{0},
  1011  					},
  1012  				},
  1013  			},
  1014  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 2}},
  1015  			expectedErr:     "element[0].init exceeds min table size",
  1016  		},
  1017  		{
  1018  			name: "imported global derived element offset exceeds table min imported table",
  1019  			module: &Module{
  1020  				TypeSection: []FunctionType{{}},
  1021  				ImportSection: []Import{
  1022  					{Type: ExternTypeTable, DescTable: Table{}},
  1023  					{Type: ExternTypeGlobal, DescGlobal: GlobalType{ValType: ValueTypeI32}},
  1024  				},
  1025  				TableSection:    []Table{{Min: 2}},
  1026  				FunctionSection: []Index{0},
  1027  				CodeSection:     []Code{codeEnd},
  1028  				ElementSection: []ElementSegment{
  1029  					{
  1030  						OffsetExpr: ConstantExpression{Opcode: OpcodeGlobalGet, Data: []byte{0x0}},
  1031  						Init:       []Index{0},
  1032  					},
  1033  				},
  1034  			},
  1035  			importedTables:  []*TableInstance{{References: make([]Reference, 2), Min: 2}},
  1036  			importedGlobals: []*GlobalInstance{{Type: GlobalType{ValType: ValueTypeI32}, Val: 2}},
  1037  			expectedErr:     "element[0].init exceeds min table size",
  1038  		},
  1039  	}
  1040  
  1041  	for _, tt := range tests {
  1042  		tc := tt
  1043  
  1044  		t.Run(tc.name, func(t *testing.T) {
  1045  			m := &ModuleInstance{
  1046  				Tables:  append(tc.importedTables, make([]*TableInstance, len(tc.module.TableSection))...),
  1047  				Globals: tc.importedGlobals,
  1048  			}
  1049  			err := m.buildTables(tc.module, false)
  1050  			require.EqualError(t, err, tc.expectedErr)
  1051  		})
  1052  	}
  1053  }
  1054  
  1055  func TestTableInstance_Grow(t *testing.T) {
  1056  	expOnErr := uint32(0xffff_ffff) // -1 as signed i32.
  1057  	max10 := uint32(10)
  1058  	tests := []struct {
  1059  		name       string
  1060  		currentLen int
  1061  		max        *uint32
  1062  		delta, exp uint32
  1063  	}{
  1064  		{
  1065  			name:       "growing ousside 32-bit range",
  1066  			currentLen: 0x10,
  1067  			delta:      0xffff_fff0,
  1068  			exp:        expOnErr,
  1069  		},
  1070  		{
  1071  			name:       "growing zero",
  1072  			currentLen: 0,
  1073  			delta:      0,
  1074  			exp:        0,
  1075  		},
  1076  		{
  1077  			name:       "growing zero on non zero table",
  1078  			currentLen: 5,
  1079  			delta:      0,
  1080  			exp:        5,
  1081  		},
  1082  		{
  1083  			name:       "grow zero on max",
  1084  			currentLen: 10,
  1085  			delta:      0,
  1086  			max:        &max10,
  1087  			exp:        10,
  1088  		},
  1089  		{
  1090  			name:       "grow out of range beyond max",
  1091  			currentLen: 10,
  1092  			delta:      1,
  1093  			max:        &max10,
  1094  			exp:        expOnErr,
  1095  		},
  1096  		{
  1097  			name:       "grow out of range beyond max part2",
  1098  			currentLen: 10,
  1099  			delta:      100,
  1100  			max:        &max10,
  1101  			exp:        expOnErr,
  1102  		},
  1103  	}
  1104  
  1105  	for _, tt := range tests {
  1106  		tc := tt
  1107  		t.Run(tc.name, func(t *testing.T) {
  1108  			table := &TableInstance{References: make([]uintptr, tc.currentLen), Max: tc.max}
  1109  			actual := table.Grow(tc.delta, 0)
  1110  			require.Equal(t, tc.exp, actual)
  1111  		})
  1112  	}
  1113  }
  1114  
  1115  func Test_unwrapElementInitGlobalReference(t *testing.T) {
  1116  	actual, ok := unwrapElementInitGlobalReference(12345 | elementInitImportedGlobalReferenceType)
  1117  	require.True(t, ok)
  1118  	require.Equal(t, actual, uint32(12345))
  1119  
  1120  	actual, ok = unwrapElementInitGlobalReference(12345)
  1121  	require.False(t, ok)
  1122  	require.Equal(t, actual, uint32(12345))
  1123  }
  1124  
  1125  // Test_ElementInitSpecials ensures these special consts are larger than MaximumFunctionIndex so that
  1126  // they won't collide with the actual index.
  1127  func Test_ElementInitSpecials(t *testing.T) {
  1128  	require.True(t, ElementInitNullReference > MaximumFunctionIndex)
  1129  	require.True(t, elementInitImportedGlobalReferenceType > MaximumFunctionIndex)
  1130  }