| import * as assert from '../assert.js'; |
| import Builder from '../Builder.js'; |
| |
| const memSizeInPages = 1; |
| const pageSizeInBytes = 64 * 1024; |
| const memoryDescription = { initial: memSizeInPages, maximum: memSizeInPages }; |
| const emptyMemory = { initial: 0, maximum: 2 }; |
| |
| // FIXME Some corner cases are ill-specified: https://github.com/WebAssembly/design/issues/897 |
| |
| const assertMemoryAllZero = memory => { |
| const buffer = new Uint8Array(memory.buffer); |
| for (let idx = 0; idx < buffer.length; ++idx) { |
| const value = buffer[idx]; |
| assert.eq(value, 0x00); |
| } |
| }; |
| |
| (function DataSection() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", memoryDescription).End() |
| .Data() |
| .Segment([0xff, 0x2a]).Offset(4).End() |
| .Segment([0xde, 0xad, 0xbe, 0xef]).Offset(24).End() |
| .Segment([0xca, 0xfe]).Offset(25).End() // Overwrite. |
| .Segment([]).Offset(4).End() // Empty. |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| const instance = new WebAssembly.Instance(module, { imp: { memory: memory } }); |
| const buffer = new Uint8Array(memory.buffer); |
| for (let idx = 0; idx < memSizeInPages * pageSizeInBytes; ++idx) { |
| const value = buffer[idx]; |
| switch (idx) { |
| case 4: assert.eq(value, 0xff); break; |
| case 5: assert.eq(value, 0x2a); break; |
| case 24: assert.eq(value, 0xde); break; |
| case 25: assert.eq(value, 0xca); break; |
| case 26: assert.eq(value, 0xfe); break; |
| case 27: assert.eq(value, 0xef); break; |
| default: assert.eq(value, 0x00); break; |
| } |
| } |
| })(); |
| |
| (function DataSectionWithoutMemory() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Data() |
| .Segment([0xff]).Offset(0).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15 / 20: 0th Data segment has index 0 which exceeds the number of Memories 0`); |
| })(); |
| |
| (function EmptyDataSectionWithoutMemory() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Data() |
| .Segment([]).Offset(0).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15 / 19: 0th Data segment has index 0 which exceeds the number of Memories 0`); |
| })(); |
| |
| (function DataSectionBiggerThanMemory() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", memoryDescription).End() |
| .Data() |
| .Segment(Array(memSizeInPages * pageSizeInBytes + 1).fill(0xff)).Offset(0).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), WebAssembly.LinkError, `Invalid data segment initialization: segment of 65537 bytes memory of 65536 bytes, at offset 0, segment is too big (evaluating 'new WebAssembly.Instance(module, { imp: { memory: memory } })')`); |
| assertMemoryAllZero(memory); |
| })(); |
| |
| (function DataSectionOffTheEnd() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", memoryDescription).End() |
| .Data() |
| .Segment([0xff]).Offset(memSizeInPages * pageSizeInBytes).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), WebAssembly.LinkError, `Invalid data segment initialization: segment of 1 bytes memory of 65536 bytes, at offset 65536, segment writes outside of memory (evaluating 'new WebAssembly.Instance(module, { imp: { memory: memory } })')`); |
| assertMemoryAllZero(memory); |
| })(); |
| |
| (function DataSectionPartlyOffTheEnd() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", memoryDescription).End() |
| .Data() |
| .Segment([0xff, 0xff]).Offset(memSizeInPages * pageSizeInBytes - 1).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), WebAssembly.LinkError, `Invalid data segment initialization: segment of 2 bytes memory of 65536 bytes, at offset 65535, segment writes outside of memory (evaluating 'new WebAssembly.Instance(module, { imp: { memory: memory } })')`); |
| assertMemoryAllZero(memory); |
| })(); |
| |
| (function DataSectionEmptyOffTheEnd() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", memoryDescription).End() |
| .Data() |
| .Segment([]).Offset(memSizeInPages * pageSizeInBytes).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| const instance = new WebAssembly.Instance(module, { imp: { memory: memory } }); |
| assertMemoryAllZero(memory); |
| })(); |
| |
| (function DataSectionEmptyOffTheEndWithEmptyMemory() { |
| const builder = (new Builder()) |
| .Type().End() |
| .Import().Memory("imp", "memory", emptyMemory).End() |
| .Data() |
| .Segment([]).Offset(memSizeInPages * pageSizeInBytes).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(emptyMemory); |
| assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), WebAssembly.LinkError, `Invalid data segment initialization: segment of 0 bytes memory of 0 bytes, at offset 65536, segment writes outside of memory`); |
| assertMemoryAllZero(memory); |
| })(); |
| |
| (function DataSectionSeenByStart() { |
| const offset = 1024; |
| const builder = (new Builder()) |
| .Type().End() |
| .Import() |
| .Memory("imp", "memory", memoryDescription) |
| .Function("imp", "func", { params: ["i32"] }) |
| .End() |
| .Function().End() |
| .Start("foo").End() |
| .Code() |
| .Function("foo", { params: [] }) |
| .I32Const(offset) |
| .I32Load8U(0, 0) |
| .Call(0) // Calls func((i8.load(offset), align=2, offset=0). This should observe 0xff as set by the data section. |
| .End() |
| .End() |
| .Data() |
| .Segment([0xff]).Offset(offset).End() |
| .End(); |
| const bin = builder.WebAssembly().get(); |
| const module = new WebAssembly.Module(bin); |
| const memory = new WebAssembly.Memory(memoryDescription); |
| let value = 0; |
| const setter = v => value = v; |
| const instance = new WebAssembly.Instance( |
| module, |
| { |
| imp: { |
| memory: memory, |
| func: setter |
| } |
| }); |
| assert.eq(value, 0xff); |
| const buffer = new Uint8Array(memory.buffer); |
| for (let idx = 0; idx < memSizeInPages * pageSizeInBytes; ++idx) { |
| const value = buffer[idx]; |
| if (idx == offset) |
| assert.eq(value, 0xff); |
| else |
| assert.eq(value, 0x00); |
| } |
| })(); |