const magicError = /failed to match magic number/; const unknownSection = /expected custom section/;
function sectionError(section) { return RegExp(`failed to start ${section} section`);
}
function versionError(actual) { var expect = encodingVersion; var str = `binary version 0x${actual.toString(16)} does not match expected version 0x${expect.toString(16)}`; return RegExp(str);
}
const U32MAX_LEB = [255, 255, 255, 255, 15];
const wasmEval = (code, imports) => new WebAssembly.Instance(new Module(code), imports).exports;
wasmEval(moduleWithSections([tableSection(0)]));
wasmEval(moduleWithSections([elemSection([])]));
wasmEval(moduleWithSections([tableSection(0), elemSection([])]));
wasmEval(moduleWithSections([tableSection(1), elemSection([{offset:1, elems:[]}])]));
assertErrorMessage(() => wasmEval(moduleWithSections([tableSection(1), elemSection([{offset:0, elems:[0]}])])), CompileError, /element index out of range/);
wasmEval(moduleWithSections([v2vSigSection, declSection([0]), tableSection(1), elemSection([{offset:0, elems:[0]}]), bodySection([v2vBody])]));
wasmEval(moduleWithSections([v2vSigSection, declSection([0]), tableSection(2), elemSection([{offset:0, elems:[0,0]}]), bodySection([v2vBody])]));
assertErrorMessage(() => wasmEval(moduleWithSections([v2vSigSection, declSection([0]), tableSection(2), elemSection([{offset:0, elems:[0,1]}]), bodySection([v2vBody])])), CompileError, /element index out of range/);
wasmEval(moduleWithSections([v2vSigSection, declSection([0,0,0]), tableSection(4), elemSection([{offset:0, elems:[0,1,0,2]}]), bodySection([v2vBody, v2vBody, v2vBody])]));
wasmEval(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection(3), elemSection([{offset:0,elems:[0,1,2]}]), bodySection([v2vBody, v2vBody, v2vBody])]));
wasmEval(moduleWithSections([tableSection0()]));
wasmEval(moduleWithSections([memorySection(0)]));
function memorySection2() { var body = [];
body.push(...varU32(2)); // number of memories
body.push(...varU32(0x0));
body.push(...varU32(0));
body.push(...varU32(0x0));
body.push(...varU32(0)); return { name: memoryId, body };
}
wasmEval(moduleWithSections([memorySection0()])); if (wasmMultiMemoryEnabled()) {
wasmEval(moduleWithSections([memorySection2()]));
} else {
assertErrorMessage(() => wasmEval(moduleWithSections([memorySection2()])), CompileError, /number of memories must be at most one/);
}
// Test early 'end' const bodyMismatch = /(function body length mismatch)|(operators remaining after end of function)/;
assertErrorMessage(() => wasmEval(moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[EndCode]})])])), CompileError, bodyMismatch);
assertErrorMessage(() => wasmEval(moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[UnreachableCode,EndCode]})])])), CompileError, bodyMismatch);
assertErrorMessage(() => wasmEval(moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[EndCode,UnreachableCode]})])])), CompileError, bodyMismatch);
// Ignore errors in name section. var tooBigNameSection = {
name: userDefinedId,
body: [...string(nameName), ...varU32(Math.pow(2, 31))] // declare 2**31 functions.
};
wasmEval(moduleWithSections([tooBigNameSection]));
// Custom sections must have valid UTF-8 names
assertErrorMessage(() => wasmEval(toU8([0,97,115,109,1,0,0,0,0,3,2,254,255,])), CompileError, /failed to start custom section/);
// Skip custom sections before any expected section var customDefSec = customSection("wee", 42, 13); var declSec = declSection([0]); var bodySec = bodySection([v2vBody]); var nameSec = nameSection([funcNameSubsection([{name:'hi'}])]);
wasmEval(moduleWithSections([customDefSec, v2vSigSection, declSec, bodySec]));
wasmEval(moduleWithSections([v2vSigSection, customDefSec, declSec, bodySec]));
wasmEval(moduleWithSections([v2vSigSection, declSec, customDefSec, bodySec]));
wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, customDefSec]));
wasmEval(moduleWithSections([customDefSec, customDefSec, v2vSigSection, declSec, bodySec]));
wasmEval(moduleWithSections([customDefSec, customDefSec, v2vSigSection, customDefSec, declSec, customDefSec, bodySec]));
// custom sections reflection: function checkCustomSection(buf, val) {
assertEq(buf instanceof ArrayBuffer, true);
assertEq(buf.byteLength, 1);
assertEq(new Uint8Array(buf)[0], val);
} var custom1 = customSection("one", 1); var custom2 = customSection("one", 2); var custom3 = customSection("two", 3); var custom4 = customSection("three", 4); var custom5 = customSection("three", 5); var custom6 = customSection("three", 6); var m = new Module(moduleWithSections([custom1, v2vSigSection, custom2, declSec, custom3, bodySec, custom4, nameSec, custom5, custom6])); var arr = Module.customSections(m, "one");
assertEq(arr.length, 2);
checkCustomSection(arr[0], 1);
checkCustomSection(arr[1], 2); var arr = Module.customSections(m, "two");
assertEq(arr.length, 1);
checkCustomSection(arr[0], 3); var arr = Module.customSections(m, "three");
assertEq(arr.length, 3);
checkCustomSection(arr[0], 4);
checkCustomSection(arr[1], 5);
checkCustomSection(arr[2], 6); var arr = Module.customSections(m, "name");
assertEq(arr.length, 1);
assertEq(arr[0].byteLength, nameSec.body.length - 5 /* 4name */);
// Provide a module name but no function names.
assertErrorMessage(() => wasmEval(moduleWithSections([
v2vSigSection,
declSection([0]),
exportSection([{funcIndex: 0, name: "f"}]),
bodySection([funcBody({locals:[], body:[UnreachableCode]})]),
nameSection([moduleNameSubsection('hi')])])
).f(), RuntimeError, /unreachable/);
// Diagnose invalid block signature types. for (var bad of [0xff, 1, 0x3f])
assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, bad, EndCode]})])])), CompileError, /(invalid .*block type)|(unknown type)/);
const multiValueModule = moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, 0, EndCode]})])]); // In this test module, 0 denotes a void-to-void block type.
assertEq(WebAssembly.validate(multiValueModule), true);
// Ensure all invalid opcodes are rejected. Note that the game here (and for // the prefixed cases below) is to present only opcodes which will be rejected by // *both* Baseline and Ion. for (let op of undefinedOpcodes) {
let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[op]})])]);
assertErrorMessage(() => wasmEval(binary), CompileError, /((unrecognized|Unknown) opcode)|(tail calls support is not enabled)|(Exceptions support is not enabled)|(Unexpected EOF)/);
assertEq(WebAssembly.validate(binary), false);
}
// Prefixed opcodes
function checkIllegalPrefixed(prefix, opcode) {
let binary = moduleWithSections([v2vSigSection,
declSection([0]),
bodySection([funcBody({locals:[],
body:[prefix, ...varU32(opcode)]})])]);
assertErrorMessage(() => wasmEval(binary), CompileError, /((unrecognized|Unknown) opcode)|(Unknown.*subopcode)|(Unexpected EOF)|(SIMD support is not enabled)|(invalid lane index)/);
assertEq(WebAssembly.validate(binary), false);
}
// Illegal MozPrefix opcodes (all of them) for (let i = 0; i < 256; i++)
checkIllegalPrefixed(MozPrefix, i);
for (let prefix of [ThreadPrefix, MiscPrefix, SimdPrefix, MozPrefix]) { // Prefix without a subsequent opcode. We must ask funcBody not to add an // End code after the prefix, so the body really is just the prefix byte.
let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[prefix]}, /*withEndCode=*/false)])]);
assertErrorMessage(() => wasmEval(binary), CompileError, /(unable to read opcode)|(Unexpected EOF)|(Unknown opcode)/);
assertEq(WebAssembly.validate(binary), false);
}
// Checking stack trace. function runStackTraceTest(moduleName, funcNames, expectedName) { var sections = [
sigSection([v2vSig]),
importSection([{sigIndex:0, module:"env", func:"callback"}]),
declSection([0]),
exportSection([{funcIndex:1, name: "run"}]),
bodySection([funcBody({locals: [], body: [CallCode, varU32(0)]})]),
customSection("whoa"),
customSection("wee", 42),
]; if (moduleName || funcNames) { var subsections = []; if (moduleName)
subsections.push(moduleNameSubsection(moduleName)); if (funcNames)
subsections.push(funcNameSubsection(funcNames));
sections.push(nameSection(subsections));
}
sections.push(customSection("yay", 13));
var result = ""; var callback = () => {
result = extractStackFrameFunction(new Error().stack.split('\n')[1]);
};
wasmEval(moduleWithSections(sections), {"env": { callback }}).run();
assertEq(result, expectedName);
};
// Enable and disable Gecko profiling mode, to ensure all live instances // names won't make us crash.
enableGeckoProfiling();
disableGeckoProfiling();