// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --experimental-wasm-bulk-memory load("test/mjsunit/wasm/wasm-module-builder.js"); (function TestPassiveDataSegment() { const builder = new WasmModuleBuilder(); builder.addMemory(1, 1, false); builder.addPassiveDataSegment([0, 1, 2]); builder.addPassiveDataSegment([3, 4]); // Should not throw. builder.instantiate(); })(); (function TestPassiveElementSegment() { const builder = new WasmModuleBuilder(); builder.addFunction('f', kSig_v_v).addBody([]); builder.setTableBounds(1, 1); builder.addPassiveElementSegment([0, 0, 0]); builder.addPassiveElementSegment([0, 0]); // Should not throw. builder.instantiate(); })(); function getMemoryInit(mem, segment_data) { const builder = new WasmModuleBuilder(); builder.addImportedMemory("", "mem", 0); builder.addPassiveDataSegment(segment_data); builder.addFunction('init', kSig_v_iii) .addBody([ kExprGetLocal, 0, // Dest. kExprGetLocal, 1, // Source. kExprGetLocal, 2, // Size in bytes. kNumericPrefix, kExprMemoryInit, 0, // Data segment index. 0, // Memory index. ]) .exportAs('init'); return builder.instantiate({'': {mem}}).exports.init; } (function TestMemoryInitOutOfBoundsGrow() { const mem = new WebAssembly.Memory({initial: 1}); // Create a data segment that has a length of kPageSize. const memoryInit = getMemoryInit(mem, new Array(kPageSize)); mem.grow(1); // Works properly after grow. memoryInit(kPageSize, 0, 1000); // Traps at new boundary. assertTraps( kTrapMemOutOfBounds, () => memoryInit(kPageSize + 1, 0, kPageSize)); })(); (function TestMemoryInitOnActiveSegment() { const builder = new WasmModuleBuilder(); builder.addMemory(1); builder.addPassiveDataSegment([1, 2, 3]); builder.addDataSegment(0, [4, 5, 6]); builder.addFunction('init', kSig_v_v) .addBody([ kExprI32Const, 0, // Dest. kExprI32Const, 0, // Source. kExprI32Const, 0, // Size in bytes. kNumericPrefix, kExprMemoryInit, 1, // Data segment index. 0, // Memory index. ]) .exportAs('init'); // Instantiation succeeds, because using memory.init with an active segment // is a trap, not a validation error. const instance = builder.instantiate(); assertTraps(kTrapDataSegmentDropped, () => instance.exports.init()); })(); (function TestDataDropOnActiveSegment() { const builder = new WasmModuleBuilder(); builder.addMemory(1); builder.addPassiveDataSegment([1, 2, 3]); builder.addDataSegment(0, [4, 5, 6]); builder.addFunction('drop', kSig_v_v) .addBody([ kNumericPrefix, kExprDataDrop, 1, // Data segment index. ]) .exportAs('drop'); const instance = builder.instantiate(); assertTraps(kTrapDataSegmentDropped, () => instance.exports.drop()); })(); function getMemoryCopy(mem) { const builder = new WasmModuleBuilder(); builder.addImportedMemory("", "mem", 0); builder.addFunction("copy", kSig_v_iii).addBody([ kExprGetLocal, 0, // Dest. kExprGetLocal, 1, // Source. kExprGetLocal, 2, // Size in bytes. kNumericPrefix, kExprMemoryCopy, 0, 0, ]).exportAs("copy"); return builder.instantiate({'': {mem}}).exports.copy; } (function TestMemoryCopyOutOfBoundsGrow() { const mem = new WebAssembly.Memory({initial: 1}); const memoryCopy = getMemoryCopy(mem); mem.grow(1); // Works properly after grow. memoryCopy(0, kPageSize, 1000); // Traps at new boundary. assertTraps( kTrapMemOutOfBounds, () => memoryCopy(0, kPageSize + 1, kPageSize)); })(); function getMemoryFill(mem) { const builder = new WasmModuleBuilder(); builder.addImportedMemory("", "mem", 0); builder.addFunction("fill", kSig_v_iii).addBody([ kExprGetLocal, 0, // Dest. kExprGetLocal, 1, // Byte value. kExprGetLocal, 2, // Size. kNumericPrefix, kExprMemoryFill, 0, ]).exportAs("fill"); return builder.instantiate({'': {mem}}).exports.fill; } (function TestMemoryFillOutOfBoundsGrow() { const mem = new WebAssembly.Memory({initial: 1}); const memoryFill = getMemoryFill(mem); const v = 123; mem.grow(1); // Works properly after grow. memoryFill(kPageSize, v, 1000); // Traps at new boundary. assertTraps( kTrapMemOutOfBounds, () => memoryFill(kPageSize + 1, v, kPageSize)); })(); (function TestElemDropActive() { const builder = new WasmModuleBuilder(); builder.setTableBounds(5, 5); builder.addElementSegment(0, 0, false, [0, 0, 0]); builder.addFunction('drop', kSig_v_v) .addBody([ kNumericPrefix, kExprElemDrop, 0, // Element segment index. ]) .exportAs('drop'); const instance = builder.instantiate(); assertTraps(kTrapElemSegmentDropped, () => instance.exports.drop()); })(); (function TestLazyDataSegmentBoundsCheck() { const memory = new WebAssembly.Memory({initial: 1}); const view = new Uint8Array(memory.buffer); const builder = new WasmModuleBuilder(); builder.addImportedMemory('m', 'memory', 1); builder.addDataSegment(kPageSize - 1, [42, 42]); builder.addDataSegment(0, [111, 111]); assertEquals(0, view[kPageSize - 1]); // Instantiation fails, but still modifies memory. assertThrows(() => builder.instantiate({m: {memory}}), WebAssembly.LinkError); assertEquals(42, view[kPageSize - 1]); // The second segment is not initialized. assertEquals(0, view[0]); })(); (function TestLazyElementSegmentBoundsCheck() { const table = new WebAssembly.Table({initial: 3, element: 'anyfunc'}); const builder = new WasmModuleBuilder(); builder.addImportedTable('m', 'table', 1); const f = builder.addFunction('f', kSig_i_v).addBody([kExprI32Const, 42]); const tableIndex = 0; const isGlobal = false; builder.addElementSegment(tableIndex, 2, isGlobal, [f.index, f.index]); builder.addElementSegment(tableIndex, 0, isGlobal, [f.index, f.index]); assertEquals(null, table.get(0)); assertEquals(null, table.get(1)); assertEquals(null, table.get(2)); // Instantiation fails, but still modifies the table. assertThrows(() => builder.instantiate({m: {table}}), WebAssembly.LinkError); // The second segment is not initialized. assertEquals(null, table.get(0)); assertEquals(null, table.get(1)); assertEquals(42, table.get(2)()); })(); (function TestLazyDataAndElementSegments() { const table = new WebAssembly.Table({initial: 1, element: 'anyfunc'}); const memory = new WebAssembly.Memory({initial: 1}); const view = new Uint8Array(memory.buffer); const builder = new WasmModuleBuilder(); builder.addImportedMemory('m', 'memory', 1); builder.addImportedTable('m', 'table', 1); const f = builder.addFunction('f', kSig_i_v).addBody([kExprI32Const, 42]); const tableIndex = 0; const isGlobal = false; builder.addElementSegment(tableIndex, 0, isGlobal, [f.index, f.index]); builder.addDataSegment(0, [42]); // Instantiation fails, but still modifies the table. The memory is not // modified, since data segments are initialized after element segments. assertThrows( () => builder.instantiate({m: {memory, table}}), WebAssembly.LinkError); assertEquals(42, table.get(0)()); assertEquals(0, view[0]); })();