1 package binary
2
3 import (
4 "bytes"
5 "strconv"
6 "testing"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/testing/require"
10 "github.com/tetratelabs/wazero/internal/wasm"
11 )
12
13 func Test_ensureElementKindFuncRef(t *testing.T) {
14 require.NoError(t, ensureElementKindFuncRef(bytes.NewReader([]byte{0x0})))
15 require.Error(t, ensureElementKindFuncRef(bytes.NewReader([]byte{0x1})))
16 }
17
18 func Test_decodeElementInitValueVector(t *testing.T) {
19 tests := []struct {
20 in []byte
21 exp []wasm.Index
22 expErr string
23 }{
24 {
25 in: []byte{0},
26 exp: []wasm.Index{},
27 },
28 {
29 in: []byte{5, 1, 2, 3, 4, 5},
30 exp: []wasm.Index{1, 2, 3, 4, 5},
31 },
32 {
33 in: []byte{
34 1,
35 0xff, 0xff, 0xff, 0xff, 0xf,
36 },
37 expErr: "too large function index in Element init: 4294967295",
38 },
39 }
40
41 for i, tt := range tests {
42 tc := tt
43 t.Run(strconv.Itoa(i), func(t *testing.T) {
44 actual, err := decodeElementInitValueVector(bytes.NewReader(tc.in))
45 if tc.expErr != "" {
46 require.EqualError(t, err, tc.expErr)
47 } else {
48 require.NoError(t, err)
49 require.Equal(t, tc.exp, actual)
50 }
51 })
52 }
53 }
54
55 func Test_decodeElementConstExprVector(t *testing.T) {
56 tests := []struct {
57 in []byte
58 refType wasm.RefType
59 exp []wasm.Index
60 features api.CoreFeatures
61 }{
62 {
63 in: []byte{0},
64 exp: []wasm.Index{},
65 refType: wasm.RefTypeFuncref,
66 features: api.CoreFeatureBulkMemoryOperations,
67 },
68 {
69 in: []byte{
70 2,
71 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
72 wasm.OpcodeRefFunc, 100, wasm.OpcodeEnd,
73 },
74 exp: []wasm.Index{wasm.ElementInitNullReference, 100},
75 refType: wasm.RefTypeFuncref,
76 features: api.CoreFeatureBulkMemoryOperations,
77 },
78 {
79 in: []byte{
80 4,
81 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
82 wasm.OpcodeRefFunc,
83 0x80, 0x7f,
84 wasm.OpcodeEnd,
85 wasm.OpcodeGlobalGet, 1, wasm.OpcodeEnd,
86 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
87 },
88 exp: []wasm.Index{
89 wasm.ElementInitNullReference,
90 16256,
91 wasm.ElementInitImportedGlobalFunctionReference | 1,
92 wasm.ElementInitNullReference,
93 },
94 refType: wasm.RefTypeFuncref,
95 features: api.CoreFeatureBulkMemoryOperations,
96 },
97 {
98 in: []byte{
99 2,
100 wasm.OpcodeRefNull, wasm.RefTypeExternref, wasm.OpcodeEnd,
101 wasm.OpcodeRefNull, wasm.RefTypeExternref, wasm.OpcodeEnd,
102 },
103 exp: []wasm.Index{wasm.ElementInitNullReference, wasm.ElementInitNullReference},
104 refType: wasm.RefTypeExternref,
105 features: api.CoreFeatureBulkMemoryOperations,
106 },
107 }
108
109 for i, tt := range tests {
110 tc := tt
111 t.Run(strconv.Itoa(i), func(t *testing.T) {
112 actual, err := decodeElementConstExprVector(bytes.NewReader(tc.in), tc.refType, tc.features)
113 require.NoError(t, err)
114 require.Equal(t, tc.exp, actual)
115 })
116 }
117 }
118
119 func Test_decodeElementConstExprVector_errors(t *testing.T) {
120 tests := []struct {
121 name string
122 in []byte
123 refType wasm.RefType
124 expErr string
125 features api.CoreFeatures
126 }{
127 {
128 name: "eof",
129 expErr: "failed to get the size of constexpr vector: EOF",
130 },
131 {
132 name: "feature",
133 in: []byte{1, wasm.OpcodeRefNull, wasm.RefTypeExternref, wasm.OpcodeEnd},
134 expErr: "ref.null is not supported as feature \"bulk-memory-operations\" is disabled",
135 },
136 {
137 name: "type mismatch - ref.null",
138 in: []byte{1, wasm.OpcodeRefNull, wasm.RefTypeExternref, wasm.OpcodeEnd},
139 refType: wasm.RefTypeFuncref,
140 features: api.CoreFeaturesV2,
141 expErr: "element type mismatch: want funcref, but constexpr has externref",
142 },
143 {
144 name: "type mismatch - ref.null",
145 in: []byte{1, wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd},
146 refType: wasm.RefTypeExternref,
147 features: api.CoreFeaturesV2,
148 expErr: "element type mismatch: want externref, but constexpr has funcref",
149 },
150 {
151 name: "invalid ref type",
152 in: []byte{1, wasm.OpcodeRefNull, 0xff, wasm.OpcodeEnd},
153 refType: wasm.RefTypeExternref,
154 features: api.CoreFeaturesV2,
155 expErr: "invalid type for ref.null: 0xff",
156 },
157 {
158 name: "type mismatch - ref.fuc",
159 in: []byte{1, wasm.OpcodeRefFunc, 0, wasm.OpcodeEnd},
160 refType: wasm.RefTypeExternref,
161 features: api.CoreFeaturesV2,
162 expErr: "element type mismatch: want externref, but constexpr has funcref",
163 },
164 {
165 name: "too large index - ref.fuc",
166 in: []byte{1, wasm.OpcodeRefFunc, 0xff, 0xff, 0xff, 0xff, 0xf, wasm.OpcodeEnd},
167 refType: wasm.RefTypeFuncref,
168 features: api.CoreFeaturesV2,
169 expErr: "too large function index in Element init: 4294967295",
170 },
171 {
172 name: "type mismatch - global.get",
173 in: []byte{1, wasm.OpcodeGlobalGet, 0, wasm.OpcodeEnd},
174 refType: wasm.RefTypeExternref,
175 features: api.CoreFeaturesV2,
176 expErr: "element type mismatch: want externref, but requires funcref",
177 },
178 }
179
180 for _, tt := range tests {
181 tc := tt
182 t.Run(tc.name, func(t *testing.T) {
183 _, err := decodeElementConstExprVector(bytes.NewReader(tc.in), tc.refType, tc.features)
184 require.EqualError(t, err, tc.expErr)
185 })
186 }
187 }
188
189 func TestDecodeElementSegment(t *testing.T) {
190 tests := []struct {
191 name string
192 in []byte
193 exp wasm.ElementSegment
194 expErr string
195 features api.CoreFeatures
196 }{
197 {
198 name: "legacy",
199 in: []byte{
200 0,
201
202 wasm.OpcodeI32Const, 1, wasm.OpcodeEnd,
203
204 5, 1, 2, 3, 4, 5,
205 },
206 exp: wasm.ElementSegment{
207 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{1}},
208 Init: []wasm.Index{1, 2, 3, 4, 5},
209 Mode: wasm.ElementModeActive,
210 Type: wasm.RefTypeFuncref,
211 },
212 features: api.CoreFeatureBulkMemoryOperations,
213 },
214 {
215 name: "legacy multi byte const expr data",
216 in: []byte{
217 0,
218
219 wasm.OpcodeI32Const, 0x80, 0, wasm.OpcodeEnd,
220
221 5, 1, 2, 3, 4, 5,
222 },
223 exp: wasm.ElementSegment{
224 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 0}},
225 Init: []wasm.Index{1, 2, 3, 4, 5},
226 Mode: wasm.ElementModeActive,
227 Type: wasm.RefTypeFuncref,
228 },
229 features: api.CoreFeatureBulkMemoryOperations,
230 },
231 {
232 name: "passive value vector",
233 in: []byte{
234 1,
235 0,
236
237 5, 1, 2, 3, 4, 5,
238 },
239 exp: wasm.ElementSegment{
240 Init: []wasm.Index{1, 2, 3, 4, 5},
241 Mode: wasm.ElementModePassive,
242 Type: wasm.RefTypeFuncref,
243 },
244 features: api.CoreFeatureBulkMemoryOperations,
245 },
246 {
247 name: "active with table index encoded.",
248 in: []byte{
249 2,
250 0,
251
252 wasm.OpcodeI32Const, 0x80, 0, wasm.OpcodeEnd,
253 0,
254
255 5, 1, 2, 3, 4, 5,
256 },
257 exp: wasm.ElementSegment{
258 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 0}},
259 Init: []wasm.Index{1, 2, 3, 4, 5},
260 Mode: wasm.ElementModeActive,
261 Type: wasm.RefTypeFuncref,
262 },
263 features: api.CoreFeatureBulkMemoryOperations,
264 },
265 {
266 name: "active with non zero table index encoded.",
267 in: []byte{
268 2,
269 10,
270
271 wasm.OpcodeI32Const, 0x80, 0, wasm.OpcodeEnd,
272 0,
273
274 5, 1, 2, 3, 4, 5,
275 },
276 exp: wasm.ElementSegment{
277 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 0}},
278 Init: []wasm.Index{1, 2, 3, 4, 5},
279 Mode: wasm.ElementModeActive,
280 Type: wasm.RefTypeFuncref,
281 TableIndex: 10,
282 },
283 features: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
284 },
285 {
286 name: "active with non zero table index encoded but reference-types disabled",
287 in: []byte{
288 2,
289 10,
290
291 wasm.OpcodeI32Const, 0x80, 0, wasm.OpcodeEnd,
292 0,
293
294 5, 1, 2, 3, 4, 5,
295 },
296 expErr: `table index must be zero but was 10: feature "reference-types" is disabled`,
297 features: api.CoreFeatureBulkMemoryOperations,
298 },
299 {
300 name: "declarative",
301 in: []byte{
302 3,
303 0,
304
305 5, 1, 2, 3, 4, 5,
306 },
307 exp: wasm.ElementSegment{
308 Init: []wasm.Index{1, 2, 3, 4, 5},
309 Mode: wasm.ElementModeDeclarative,
310 Type: wasm.RefTypeFuncref,
311 },
312 features: api.CoreFeatureBulkMemoryOperations,
313 },
314 {
315 name: "active const expr vector",
316 in: []byte{
317 4,
318
319 wasm.OpcodeI32Const, 0x80, 1, wasm.OpcodeEnd,
320
321 3,
322 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
323 wasm.OpcodeRefFunc,
324 0x80, 0x7f,
325 wasm.OpcodeEnd,
326 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
327 },
328 exp: wasm.ElementSegment{
329 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 1}},
330 Init: []wasm.Index{wasm.ElementInitNullReference, 16256, wasm.ElementInitNullReference},
331 Mode: wasm.ElementModeActive,
332 Type: wasm.RefTypeFuncref,
333 },
334 features: api.CoreFeatureBulkMemoryOperations,
335 },
336 {
337 name: "passive const expr vector - funcref",
338 in: []byte{
339 5,
340 wasm.RefTypeFuncref,
341
342 3,
343 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
344 wasm.OpcodeRefFunc,
345 0x80, 0x7f,
346 wasm.OpcodeEnd,
347 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
348 },
349 exp: wasm.ElementSegment{
350 Init: []wasm.Index{wasm.ElementInitNullReference, 16256, wasm.ElementInitNullReference},
351 Mode: wasm.ElementModePassive,
352 Type: wasm.RefTypeFuncref,
353 },
354 features: api.CoreFeatureBulkMemoryOperations,
355 },
356 {
357 name: "passive const expr vector - unknown ref type",
358 in: []byte{
359 5,
360 0xff,
361 },
362 expErr: `ref type must be funcref or externref for element as of WebAssembly 2.0`,
363 features: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
364 },
365 {
366 name: "active with table index and const expr vector",
367 in: []byte{
368 6,
369 0,
370
371 wasm.OpcodeI32Const, 0x80, 1, wasm.OpcodeEnd,
372 wasm.RefTypeFuncref,
373
374 3,
375 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
376 wasm.OpcodeRefFunc,
377 0x80, 0x7f,
378 wasm.OpcodeEnd,
379 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
380 },
381 exp: wasm.ElementSegment{
382 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 1}},
383 Init: []wasm.Index{wasm.ElementInitNullReference, 16256, wasm.ElementInitNullReference},
384 Mode: wasm.ElementModeActive,
385 Type: wasm.RefTypeFuncref,
386 },
387 features: api.CoreFeatureBulkMemoryOperations,
388 },
389 {
390 name: "active with non zero table index and const expr vector",
391 in: []byte{
392 6,
393 10,
394
395 wasm.OpcodeI32Const, 0x80, 1, wasm.OpcodeEnd,
396 wasm.RefTypeFuncref,
397
398 3,
399 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
400 wasm.OpcodeRefFunc,
401 0x80, 0x7f,
402 wasm.OpcodeEnd,
403 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
404 },
405 exp: wasm.ElementSegment{
406 OffsetExpr: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x80, 1}},
407 Init: []wasm.Index{wasm.ElementInitNullReference, 16256, wasm.ElementInitNullReference},
408 Mode: wasm.ElementModeActive,
409 Type: wasm.RefTypeFuncref,
410 TableIndex: 10,
411 },
412 features: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
413 },
414 {
415 name: "active with non zero table index and const expr vector but feature disabled",
416 in: []byte{
417 6,
418 10,
419
420 wasm.OpcodeI32Const, 0x80, 1, wasm.OpcodeEnd,
421 wasm.RefTypeFuncref,
422
423 3,
424 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
425 wasm.OpcodeRefFunc,
426 0x80, 0x80, 0x80, 0x4f,
427 wasm.OpcodeEnd,
428 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
429 },
430 expErr: `table index must be zero but was 10: feature "reference-types" is disabled`,
431 features: api.CoreFeatureBulkMemoryOperations,
432 },
433 {
434 name: "declarative const expr vector",
435 in: []byte{
436 7,
437 wasm.RefTypeFuncref,
438
439 2,
440 wasm.OpcodeRefNull, wasm.RefTypeFuncref, wasm.OpcodeEnd,
441 wasm.OpcodeRefFunc,
442 0x80, 0x7f,
443 wasm.OpcodeEnd,
444 },
445 exp: wasm.ElementSegment{
446 Init: []wasm.Index{wasm.ElementInitNullReference, 16256},
447 Mode: wasm.ElementModeDeclarative,
448 Type: wasm.RefTypeFuncref,
449 },
450 features: api.CoreFeatureBulkMemoryOperations,
451 },
452 }
453
454 for _, tt := range tests {
455 tc := tt
456 t.Run(tc.name, func(t *testing.T) {
457 var actual wasm.ElementSegment
458 err := decodeElementSegment(bytes.NewReader(tc.in), tc.features, &actual)
459 if tc.expErr != "" {
460 require.EqualError(t, err, tc.expErr)
461 } else {
462 require.NoError(t, err)
463 require.Equal(t, actual, tc.exp)
464 }
465 })
466 }
467 }
468
469 func TestDecodeElementSegment_errors(t *testing.T) {
470 var actual wasm.ElementSegment
471 err := decodeElementSegment(bytes.NewReader([]byte{1}), api.CoreFeatureMultiValue, &actual)
472 require.EqualError(t, err, `non-zero prefix for element segment is invalid as feature "bulk-memory-operations" is disabled`)
473 }
474
View as plain text