| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Flags: --expose-wasm --allow-natives-syntax |
| |
| load("test/mjsunit/wasm/wasm-module-builder.js"); |
| |
| function builder() { |
| return new WasmModuleBuilder; |
| } |
| |
| function assertCompileError(bytes, msg) { |
| assertThrows( |
| () => new WebAssembly.Module(bytes), WebAssembly.CompileError, |
| 'WebAssembly.Module(): ' + msg); |
| assertThrowsAsync( |
| WebAssembly.compile(bytes), WebAssembly.CompileError, |
| 'WebAssembly.compile(): ' + msg); |
| } |
| |
| function assertInstantiateError(error, bytes, imports = {}, msg) { |
| assertThrows( |
| () => new WebAssembly.Instance(new WebAssembly.Module(bytes), imports), |
| error, 'WebAssembly.Instance(): ' + msg); |
| assertThrowsAsync( |
| WebAssembly.instantiate(bytes, imports), error, |
| 'WebAssembly.instantiate(): ' + msg); |
| } |
| |
| // default imports to {} so we get LinkError by default, thus allowing us to |
| // distinguish the TypeError we want to catch |
| function assertTypeError(bytes, imports = {}, msg) { |
| assertInstantiateError(TypeError, bytes, imports, msg); |
| } |
| |
| function assertLinkError(bytes, imports, msg) { |
| assertInstantiateError(WebAssembly.LinkError, bytes, imports, msg); |
| } |
| |
| function assertConversionError(bytes, imports, msg) { |
| let instance = |
| new WebAssembly.Instance(new WebAssembly.Module(bytes), imports); |
| assertThrows(() => instance.exports.run(), TypeError, msg); |
| } |
| |
| (function TestDecodingError() { |
| print(arguments.callee.name); |
| assertCompileError(bytes(), 'BufferSource argument is empty'); |
| assertCompileError(bytes('X'), 'expected 4 bytes, fell off end @+0'); |
| assertCompileError( |
| bytes('\0x00asm'), |
| 'expected magic word 00 61 73 6d, found 00 78 30 30 @+0'); |
| })(); |
| |
| (function TestValidationError() { |
| print(arguments.callee.name); |
| let f_error = msg => 'Compiling function #0:"f" failed: ' + msg; |
| assertCompileError( |
| builder().addFunction('f', kSig_i_v).end().toBuffer(), |
| f_error('function body must end with "end" opcode @+24')); |
| assertCompileError( |
| builder().addFunction('f', kSig_i_v).addBody([kExprReturn]) |
| .end().toBuffer(), |
| f_error('expected 1 elements on the stack for return, found 0 @+24')); |
| assertCompileError(builder().addFunction('f', kSig_v_v).addBody([ |
| kExprGetLocal, 0 |
| ]).end().toBuffer(), f_error('invalid local index: 0 @+24')); |
| assertCompileError( |
| builder().addStart(0).toBuffer(), |
| 'start function index 0 out of bounds (0 entries) @+10'); |
| })(); |
| |
| function import_error(index, module, func, msg) { |
| let full_msg = 'Import #' + index + ' module=\"' + module + '\"'; |
| if (func !== undefined) full_msg += ' function=\"' + func + '\"'; |
| return full_msg + ' error: ' + msg; |
| } |
| |
| (function TestTypeError() { |
| print(arguments.callee.name); |
| let b = builder(); |
| b.addImport('foo', 'bar', kSig_v_v); |
| let msg = |
| import_error(0, 'foo', undefined, 'module is not an object or function'); |
| assertTypeError(b.toBuffer(), {}, msg); |
| |
| b = builder(); |
| b.addImportedGlobal('foo', 'bar', kWasmI32); |
| assertTypeError(b.toBuffer(), {}, msg); |
| |
| b = builder(); |
| b.addImportedMemory('foo', 'bar'); |
| assertTypeError(b.toBuffer(), {}, msg); |
| })(); |
| |
| (function TestLinkingError() { |
| print(arguments.callee.name); |
| let b; |
| let msg; |
| |
| b = builder(); |
| msg = import_error(0, 'foo', 'bar', 'function import requires a callable'); |
| b.addImport('foo', 'bar', kSig_v_v); |
| assertLinkError(b.toBuffer(), {foo: {}}, msg); |
| b = builder(); |
| b.addImport('foo', 'bar', kSig_v_v); |
| assertLinkError(b.toBuffer(), {foo: {bar: 9}}, msg); |
| |
| b = builder(); |
| msg = import_error( |
| 0, 'foo', 'bar', |
| 'global import must be a number or WebAssembly.Global object'); |
| b.addImportedGlobal('foo', 'bar', kWasmI32); |
| assertLinkError(b.toBuffer(), {foo: {}}, msg); |
| b = builder(); |
| b.addImportedGlobal('foo', 'bar', kWasmI32); |
| assertLinkError(b.toBuffer(), {foo: {bar: ''}}, msg); |
| b = builder(); |
| b.addImportedGlobal('foo', 'bar', kWasmI32); |
| assertLinkError(b.toBuffer(), {foo: {bar: () => 9}}, msg); |
| |
| b = builder(); |
| msg = import_error( |
| 0, 'foo', 'bar', 'memory import must be a WebAssembly.Memory object'); |
| b.addImportedMemory('foo', 'bar'); |
| assertLinkError(b.toBuffer(), {foo: {}}, msg); |
| b = builder(); |
| b.addImportedMemory('foo', 'bar', 1); |
| assertLinkError( |
| b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}}, |
| msg); |
| })(); |
| |
| (function TestTrapUnreachable() { |
| print(arguments.callee.name); |
| let instance = builder().addFunction('run', kSig_v_v) |
| .addBody([kExprUnreachable]).exportFunc().end().instantiate(); |
| assertTraps(kTrapUnreachable, instance.exports.run); |
| })(); |
| |
| (function TestTrapDivByZero() { |
| print(arguments.callee.name); |
| let instance = builder().addFunction('run', kSig_v_v).addBody( |
| [kExprI32Const, 1, kExprI32Const, 0, kExprI32DivS, kExprDrop]) |
| .exportFunc().end().instantiate(); |
| assertTraps(kTrapDivByZero, instance.exports.run); |
| })(); |
| |
| (function TestUnreachableInStart() { |
| print(arguments.callee.name); |
| |
| let b = builder().addFunction("start", kSig_v_v).addBody( |
| [kExprUnreachable]).end().addStart(0); |
| assertTraps(kTrapUnreachable, () => b.instantiate()); |
| })(); |
| |
| (function TestConversionError() { |
| print(arguments.callee.name); |
| let b = builder(); |
| b.addImport('foo', 'bar', kSig_v_l); |
| let buffer = b.addFunction('run', kSig_v_v) |
| .addBody([kExprI64Const, 0, kExprCallFunction, 0]) |
| .exportFunc() |
| .end() |
| .toBuffer(); |
| assertConversionError( |
| buffer, {foo: {bar: (l) => {}}}, kTrapMsgs[kTrapTypeError]); |
| |
| buffer = builder() |
| .addFunction('run', kSig_l_v) |
| .addBody([kExprI64Const, 0]) |
| .exportFunc() |
| .end() |
| .toBuffer(); |
| assertConversionError(buffer, {}, kTrapMsgs[kTrapTypeError]); |
| })(); |
| |
| (function InternalDebugTrace() { |
| print(arguments.callee.name); |
| var builder = new WasmModuleBuilder(); |
| var sig = builder.addType(kSig_i_dd); |
| builder.addImport("mod", "func", sig); |
| builder.addFunction("main", sig) |
| .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, 0]) |
| .exportAs("main"); |
| var main = builder.instantiate({ |
| mod: { |
| func: ()=>{%DebugTrace();} |
| } |
| }).exports.main; |
| main(); |
| })(); |
| |
| (function TestMultipleCorruptFunctions() { |
| print(arguments.callee.name); |
| // Generate a module with multiple corrupt functions. The error message must |
| // be deterministic. |
| var builder = new WasmModuleBuilder(); |
| var sig = builder.addType(kSig_v_v); |
| for (let i = 0; i < 10; ++i) { |
| builder.addFunction('f' + i, sig).addBody([kExprEnd]); |
| } |
| assertCompileError( |
| builder.toBuffer(), |
| 'Compiling function #0:"f0" failed: ' + |
| 'trailing code after function end @+33'); |
| })(); |