limits.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // Limits taken from WasmLimits.h
  6. const MaxTypes = 1000000;
  7. const MaxFunctions = 1000000;
  8. const MaxImports = 100000;
  9. const MaxExports = 100000;
  10. const MaxGlobals = 1000000;
  11. const MaxDataSegments = 100000;
  12. const MaxElementSegments = 10000000;
  13. const MaxTableSize = 10000000;
  14. const MaxStringSize = 100000;
  15. const MaxFunctionLocals = 50000;
  16. const MaxFunctionParams = 1000;
  17. const MaxBrTableElems = 1000000;
  18. const MaxMemoryInitialPages = 32767;
  19. const MaxMemoryMaximumPages = 65536;
  20. const MaxModuleSize = 1024 * 1024 * 1024;
  21. const MaxFunctionSize = 7654321;
  22. /* global assert,testRunner */ // eslint rule
  23. WScript.LoadScriptFile("../UnitTestFramework/UnitTestFramework.js");
  24. WScript.LoadScriptFile("../WasmSpec/testsuite/harness/wasm-constants.js");
  25. WScript.LoadScriptFile("../WasmSpec/testsuite/harness/wasm-module-builder.js");
  26. WScript.Flag("-off:wasmdeferred");
  27. function compile(moduleStr) {
  28. const buf = WebAssembly.wabt.convertWast2Wasm(moduleStr);
  29. return new WebAssembly.Module(buf);
  30. }
  31. const notTooLongName = "a".repeat(MaxStringSize);
  32. const tooLongName = "a".repeat(MaxStringSize + 1);
  33. function makeLimitTests(opt) {
  34. return [{
  35. name: "valid: " + opt.name,
  36. validTest: true,
  37. body() {
  38. const builder = new WasmModuleBuilder();
  39. opt.makeModule(builder, opt.limit);
  40. assert.doesNotThrow(() => new WebAssembly.Module(builder.toBuffer()), `WebAssembly should allow up to ${opt.limit} ${opt.type}`);
  41. }
  42. }, {
  43. name: "invalid: " + opt.name,
  44. invalidTest: true,
  45. body() {
  46. const builder = new WasmModuleBuilder();
  47. opt.makeModule(builder, opt.limit + 1);
  48. assert.throws(() => new WebAssembly.Module(builder.toBuffer()), WebAssembly.CompileError, `WebAssembly should not allow ${opt.limit + 1} ${opt.type}`, opt.errorMsg);
  49. }
  50. }];
  51. }
  52. const tests = [
  53. // Tests 0,1
  54. ...makeLimitTests({
  55. name: "test max types",
  56. limit: MaxTypes,
  57. type: "types",
  58. errorMsg: "Too many signatures",
  59. makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addType(kSig_v_v);}}
  60. }),
  61. // Tests 2,3
  62. ...makeLimitTests({
  63. name: "test max functions",
  64. limit: MaxFunctions,
  65. type: "functions",
  66. errorMsg: "Too many functions",
  67. makeModule: (builder, limit) => {
  68. const typeIndex = builder.addType(kSig_v_v);
  69. for (let i = 0; i < limit; ++i) {builder.addFunction(null, typeIndex).addBody([]);}
  70. }
  71. }),
  72. // Tests 4,5
  73. ...makeLimitTests({
  74. name: "test max imports",
  75. limit: MaxImports,
  76. type: "imports",
  77. errorMsg: "Too many imports",
  78. makeModule: (builder, limit) => {
  79. const typeIndex = builder.addType(kSig_v_v);
  80. for (let i = 0; i < limit; ++i) {builder.addImport("", "", typeIndex);}
  81. }
  82. }),
  83. // Tests 6,7
  84. ...makeLimitTests({
  85. name: "test max exports",
  86. limit: MaxExports,
  87. type: "exports",
  88. errorMsg: "Too many exports",
  89. makeModule: (builder, limit) => {
  90. builder.addFunction(null, kSig_v_v).addBody([]);
  91. for (let i = 0; i < limit; ++i) {builder.addExport("" + i, 0);}
  92. }
  93. }),
  94. // Tests 8,9
  95. ...makeLimitTests({
  96. name: "test max globals",
  97. limit: MaxGlobals,
  98. type: "globals",
  99. errorMsg: "Too many globals",
  100. makeModule: (builder, limit) => {for (let i = 0; i < limit; ++i) {builder.addGlobal(kWasmI32, /* mutable */ false);}}
  101. }),
  102. // Tests 10,11
  103. ...makeLimitTests({
  104. name: "test max data segments",
  105. limit: MaxDataSegments,
  106. type: "data segments",
  107. errorMsg: "Too many data segments",
  108. makeModule: (builder, limit) => {
  109. builder.addMemory(0);
  110. for (let i = 0; i < limit; ++i) {builder.addDataSegment(0, "");}
  111. }
  112. }),
  113. // Tests 12,13
  114. ...makeLimitTests({
  115. name: "test max element segments",
  116. limit: MaxElementSegments,
  117. type: "element segments",
  118. errorMsg: "Too many element segments",
  119. makeModule: (builder, limit) => {
  120. builder.addFunction(null, kSig_v_v).addBody([]);
  121. builder.setTableLength(1);
  122. builder.element_segments.length = limit;
  123. builder.element_segments.fill({base:0, is_global:false, array:[0]});
  124. }
  125. }),
  126. // Test 14
  127. {
  128. name: "test max table size",
  129. body() {
  130. assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize}));
  131. assert.doesNotThrow(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize, maximum: MaxTableSize}));
  132. assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize}));
  133. assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1}));
  134. assert.throws(() => new WebAssembly.Table({element: "anyfunc", initial: MaxTableSize + 1, maximum: MaxTableSize + 1}));
  135. assert.throws(() => new WebAssembly.Table({element: "anyfunc", maximum: MaxTableSize + 1}));
  136. assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} anyfunc))`));
  137. assert.doesNotThrow(() => compile(`(module (table ${MaxTableSize} ${MaxTableSize} anyfunc))`));
  138. assert.doesNotThrow(() => compile(`(module (table 0 ${MaxTableSize} anyfunc))`));
  139. assert.throws(() => compile(`(module (table ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
  140. assert.throws(() => compile(`(module (table ${MaxTableSize + 1} ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
  141. assert.throws(() => compile(`(module (table 0 ${MaxTableSize + 1} anyfunc))`), WebAssembly.CompileError, "table too big");
  142. }
  143. },
  144. // Test 15
  145. {
  146. name: "test custom sections with long names",
  147. body() {
  148. function makeCustomSection(name) {
  149. const customSection = new Binary();
  150. customSection.emit_section(0, section => {
  151. section.emit_string(name)
  152. section.emit_string("payload")
  153. });
  154. const builder = new WasmModuleBuilder();
  155. builder.addExplicitSection(customSection);
  156. return new WebAssembly.Module(builder.toBuffer());
  157. }
  158. assert.doesNotThrow(() => makeCustomSection(notTooLongName));
  159. assert.throws(() => makeCustomSection(tooLongName), WebAssembly.CompileError, "Name too long");
  160. }
  161. },
  162. // Test 16
  163. {
  164. name: "test exports with long names",
  165. body() {
  166. function makeExportName(name)
  167. {
  168. const builder = new WasmModuleBuilder();
  169. builder
  170. .addFunction(name, kSig_v_v)
  171. .exportFunc()
  172. .addBody([]);
  173. return new WebAssembly.Module(builder.toBuffer());
  174. }
  175. assert.doesNotThrow(() => makeExportName(notTooLongName));
  176. assert.throws(() => makeExportName(tooLongName), WebAssembly.CompileError, "Name too long");
  177. }
  178. },
  179. // Test 17
  180. {
  181. name: "test imports with long names",
  182. body() {
  183. function makeImportName(name)
  184. {
  185. const builder = new WasmModuleBuilder();
  186. builder.addImport(name, 'b', kSig_v_v);
  187. return new WebAssembly.Module(builder.toBuffer());
  188. }
  189. assert.doesNotThrow(() => makeImportName(notTooLongName));
  190. assert.throws(() => makeImportName(tooLongName), WebAssembly.CompileError, "Name too long");
  191. }
  192. },
  193. // Test 18
  194. {
  195. name: "test Name section with long names",
  196. body() {
  197. function makeName(name)
  198. {
  199. const builder = new WasmModuleBuilder();
  200. builder
  201. .addFunction(notTooLongName, kSig_v_v)
  202. .addBody([]);
  203. return new WebAssembly.Module(builder.toBuffer());
  204. }
  205. assert.doesNotThrow(() => makeName(notTooLongName));
  206. // todo:: enable test once we start using the Name section
  207. // assert.throws(() => makeName(tooLongName), WebAssembly.CompileError, "Name too long");
  208. }
  209. },
  210. // Tests 19,20
  211. ...makeLimitTests({
  212. name: "test max function locals",
  213. limit: MaxFunctionLocals,
  214. type: "locals",
  215. makeModule: (builder, limit) => {
  216. builder.addFunction(null, kSig_v_v).addLocals({i32_count: limit}).addBody([]);
  217. }
  218. }),
  219. // Tests 21,22
  220. ...makeLimitTests({
  221. name: "test max function params",
  222. limit: MaxFunctionParams,
  223. type: "params",
  224. errorMsg: "Too many arguments in signature",
  225. makeModule: (builder, limit) => {
  226. builder.addFunction(null, {params: (new Array(limit)).fill(kWasmI32), results: []}).addBody([]);
  227. }
  228. }),
  229. // Tests 23
  230. {
  231. name: "test max memory pages",
  232. body() {
  233. // We can't actually allocate so much memory on a test machine and except things to go well
  234. //assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages}));
  235. //assert.doesNotThrow(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages, maximum: MaxMemoryMaximumPages}));
  236. //assert.doesNotThrow(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages}));
  237. assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1}));
  238. assert.throws(() => new WebAssembly.Memory({initial: MaxMemoryInitialPages + 1, maximum: MaxMemoryMaximumPages + 1}));
  239. assert.throws(() => new WebAssembly.Memory({maximum: MaxMemoryMaximumPages + 1}));
  240. const makeModule = (min, max) => {
  241. const builder = new WasmModuleBuilder();
  242. builder.addMemory(min, max);
  243. return new WebAssembly.Module(builder.toBuffer());
  244. };
  245. assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages));
  246. assert.doesNotThrow(() => makeModule(MaxMemoryInitialPages, MaxMemoryMaximumPages));
  247. assert.doesNotThrow(() => makeModule(0, MaxMemoryMaximumPages));
  248. assert.throws(() => makeModule(MaxMemoryInitialPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
  249. assert.throws(() => makeModule(MaxMemoryInitialPages + 1, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Minimum memory size too big");
  250. assert.throws(() => makeModule(0, MaxMemoryMaximumPages + 1), WebAssembly.CompileError, "Maximum memory size too big");
  251. }
  252. },
  253. // Tests 24
  254. {
  255. name: "test max module size",
  256. body() {
  257. assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize)), WebAssembly.CompileError, "Malformed WASM module header");
  258. assert.throws(() => new WebAssembly.Module(new ArrayBuffer(MaxModuleSize + 1)), WebAssembly.CompileError, "Module too big");
  259. }
  260. },
  261. // Tests 25,26
  262. ...makeLimitTests({
  263. name: "test max function size",
  264. limit: MaxFunctionSize,
  265. type: "size",
  266. errorMsg: "Function body too big",
  267. makeModule: (builder, limit) => {
  268. // limit -1 (number of locals byte) -1 (endOpCode)
  269. builder.addFunction(null, kSig_v_v).addBody((new Array(limit - 2)).fill(kExprNop));
  270. }
  271. }),
  272. // todo:: test MaxBrTableElems
  273. ];
  274. WScript.LoadScriptFile("../UnitTestFramework/yargs.js");
  275. const argv = yargsParse(WScript.Arguments, {
  276. boolean: ["valid", "invalid", "verbose"],
  277. number: ["start", "end"],
  278. default: {
  279. verbose: true,
  280. valid: true,
  281. invalid: true,
  282. start: 0,
  283. end: tests.length
  284. }
  285. }).argv;
  286. const todoTests = tests
  287. .slice(argv.start, argv.end)
  288. .filter(test => (!test.invalidTest || argv.invalid) &&
  289. (!test.validTest || argv.valid));
  290. testRunner.run(todoTests, {verbose: argv.verbose});