blob: 42255c9f72ef55008a0a533fb43f9525b9b31b0c [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
// Limits taken from WasmLimits.h
const MaxTypes = 1000000;
const MaxFunctions = 1000000;
const MaxImports = 100000;
const MaxExports = 100000;
const MaxGlobals = 1000000;
const MaxDataSegments = 100000;
const MaxElementSegments = 10000000;
const MaxTableSize = 10000000;
const MaxStringSize = 100000;
const MaxFunctionLocals = 50000;
const MaxFunctionParams = 1000;
const MaxBrTableElems = 1000000;
const MaxMemoryInitialPages = 32767;
const MaxMemoryMaximumPages = 65536;
const MaxModuleSize = 1024 * 1024 * 1024;
const MaxFunctionSize = 7654321;
/* global assert,testRunner */ // eslint rule
WScript.LoadScriptFile("../UnitTestFramework/UnitTestFramework.js");
WScript.LoadScriptFile("../WasmSpec/testsuite/harness/wasm-constants.js");
WScript.LoadScriptFile("../WasmSpec/testsuite/harness/wasm-module-builder.js");
WScript.Flag("-off:wasmdeferred");
function compile(moduleStr) {
const buf = WebAssembly.wabt.convertWast2Wasm(moduleStr);
return new WebAssembly.Module(buf);
}
const notTooLongName = "a".repeat(MaxStringSize);
const tooLongName = "a".repeat(MaxStringSize + 1);
function makeLimitTests(opt) {
return [{
name: "valid: " + opt.name,
validTest: true,
body() {
const builder = new WasmModuleBuilder();
opt.makeModule(builder, opt.limit);
assert.doesNotThrow(() => new WebAssembly.Module(builder.toBuffer()), `WebAssembly should allow up to ${opt.limit} ${opt.type}`);
}
}, {
name: "invalid: " + opt.name,
invalidTest: true,
body() {
const builder = new WasmModuleBuilder();
opt.makeModule(builder, opt.limit + 1);
assert.throws(() => new WebAssembly.Module(builder.toBuffer()), WebAssembly.CompileError, `WebAssembly should not allow ${opt.limit + 1} ${opt.type}`, opt.errorMsg);
}
}];
}
const tests = [
// Tests 0,1
...makeLimitTests({
name: "test max types",
limit: MaxTypes,
type: "types",
errorMsg: "Too many signatures",
makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addType(kSig_v_v);}}
}),
// Tests 2,3
...makeLimitTests({
name: "test max functions",
limit: MaxFunctions,
type: "functions",
errorMsg: "Too many functions",
makeModule: (builder, limit) => {
const typeIndex = builder.addType(kSig_v_v);
for (let i = 0; i < limit; ++i) {builder.addFunction(null, typeIndex).addBody([]);}
}
}),
// Tests 4,5
...makeLimitTests({
name: "test max imports",
limit: MaxImports,
type: "imports",
errorMsg: "Too many imports",
makeModule: (builder, limit) => {
const typeIndex = builder.addType(kSig_v_v);
for (let i = 0; i < limit; ++i) {builder.addImport("", "", typeIndex);}
}
}),
// Tests 6,7
...makeLimitTests({
name: "test max exports",
limit: MaxExports,
type: "exports",
errorMsg: "Too many exports",
makeModule: (builder, limit) => {
builder.addFunction(null, kSig_v_v).addBody([]);
for (let i = 0; i < limit; ++i) {builder.addExport("" + i, 0);}
}
}),
// Tests 8,9
...makeLimitTests({
name: "test max globals",
limit: MaxGlobals,
type: "globals",
errorMsg: "Too many globals",
makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addGlobal(kWasmI32, /* mutable */ false);}}
}),
// Tests 10,11
...makeLimitTests({
name: "test max data segments",
limit: MaxDataSegments,
type: "data segments",
errorMsg: "Too many data segments",
makeModule: (builder, limit) => {
builder.addMemory(0);
for (let i = 0; i < limit; ++i) {builder.addDataSegment(0, "");}
}
}),
// Tests 12,13
...makeLimitTests({
name: "test max element segments",
limit: MaxElementSegments,
type: "element segments",
errorMsg: "Too many element segments",
makeModule: (builder, limit) => {
builder.addFunction(null, kSig_v_v).addBody([]);
builder.setTableLength(1);
builder.element_segments.length = limit;
builder.element_segments.fill({base:0, is_global:false, array:[0]});
}
}),
// Test 14
{
name: "test max table size",
body() {
assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize}));
assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize, maximum: MaxTableSize}));
assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize}));
assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1}));
assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1, maximum: MaxTableSize + 1}));
assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize + 1}));
assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} anyfunc))`));
assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} ${MaxTableSize} anyfunc))`));
assert.doesNotThrow(() => compile(`(module (table 0 ${MaxTableSize} anyfunc))`));
assert.throws(() => compile(`(module (table ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
assert.throws(() => compile(`(module (table ${MaxTableSize + 1} ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
assert.throws(() => compile(`(module (table 0 ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
}
},
// Test 15
{
name: "test custom sections with long names",
body() {
function makeCustomSection(name) {
const customSection = new Binary();
customSection.emit_section(0, section => {
section.emit_string(name)
section.emit_string("payload")
});
const builder = new WasmModuleBuilder();
builder.addExplicitSection(customSection);
return new WebAssembly.Module(builder.toBuffer());
}
assert.doesNotThrow(() => makeCustomSection(notTooLongName));
assert.throws(() => makeCustomSection(tooLongName), WebAssembly.CompileError, "Name too long");
}
},
// Test 16
{
name: "test exports with long names",
body() {
function makeExportName(name)
{
const builder = new WasmModuleBuilder();
builder
.addFunction(name, kSig_v_v)
.exportFunc()
.addBody([]);
return new WebAssembly.Module(builder.toBuffer());
}
assert.doesNotThrow(() => makeExportName(notTooLongName));
assert.throws(() => makeExportName(tooLongName), WebAssembly.CompileError, "Name too long");
}
},
// Test 17
{
name: "test imports with long names",
body() {
function makeImportName(name)
{
const builder = new WasmModuleBuilder();
builder.addImport(name, 'b', kSig_v_v);
return new WebAssembly.Module(builder.toBuffer());
}
assert.doesNotThrow(() => makeImportName(notTooLongName));
assert.throws(() => makeImportName(tooLongName), WebAssembly.CompileError, "Name too long");
}
},
// Test 18
{
name: "test Name section with long names",
body() {
function makeName(name)
{
const builder = new WasmModuleBuilder();
builder
.addFunction(notTooLongName, kSig_v_v)
.addBody([]);
return new WebAssembly.Module(builder.toBuffer());
}
assert.doesNotThrow(() => makeName(notTooLongName));
// todo:: enable test once we start using the Name section
// assert.throws(() => makeName(tooLongName), WebAssembly.CompileError, "Name too long");
}
},
// Tests 19,20
...makeLimitTests({
name: "test max function locals",
limit: MaxFunctionLocals,
type: "locals",
makeModule: (builder, limit) => {
builder.addFunction(null, kSig_v_v).addLocals({i32_count: limit}).addBody([]);
}
}),
// Tests 21,22
...makeLimitTests({
name: "test max function params",
limit: MaxFunctionParams,
type: "params",
errorMsg: "Too many arguments in signature",
makeModule: (builder, limit) => {
builder.addFunction(null, {params: (new Array(limit)).fill(kWasmI32), results: []}).addBody([]);
}
}),
// Tests 23
{
name: "test max memory pages",
body() {
// We can't actually allocate so much memory on a test machine and except things to go well
//assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages}));
//assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages, maximum: MaxMemoryMaximumPages}));
//assert.doesNotThrow(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages}));
assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1}));
assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1, maximum: MaxMemoryMaximumPages + 1}));
assert.throws(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages + 1}));
const makeModule = (min, max) => {
const builder = new WasmModuleBuilder();
builder.addMemory(min, max);
return new WebAssembly.Module(builder.toBuffer());
};
assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages));
assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages, MaxMemoryMaximumPages));
assert.doesNotThrow(() => makeModule(0, MaxMemoryMaximumPages));
assert.throws(() => makeModule(MaxMemoryInitialPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
assert.throws(() => makeModule(MaxMemoryInitialPages + 1, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
assert.throws(() => makeModule(0, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Maximum memory size too big");
}
},
// Tests 24
{
name: "test max module size",
body() {
assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize)), WebAssembly.CompileError, "Malformed WASM module header");
assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize + 1)), WebAssembly.CompileError, "Module too big");
}
},
// Tests 25,26
...makeLimitTests({
name: "test max function size",
limit: MaxFunctionSize,
type: "size",
errorMsg: "Function body too big",
makeModule: (builder, limit) => {
// limit -1 (number of locals byte) -1 (endOpCode)
builder.addFunction(null, kSig_v_v).addBody((new Array(limit - 2)).fill(kExprNop));
}
}),
// todo:: test MaxBrTableElems
];
WScript.LoadScriptFile("../UnitTestFrameWork/yargs.js");
const argv = yargsParse(WScript.Arguments, {
boolean: ["valid", "invalid", "verbose"],
number: ["start", "end"],
default: {
verbose: true,
valid: true,
invalid: true,
start: 0,
end: tests.length
}
}).argv;
const todoTests = tests
.slice(argv.start, argv.end)
.filter(test => (!test.invalidTest || argv.invalid) &&
(!test.validTest || argv.valid));
testRunner.run(todoTests, {verbose: argv.verbose});