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: 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: 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); } })();