errors.js 6.69 KB
Newer Older
1 2 3 4
// 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.

5
// Flags: --expose-wasm --allow-natives-syntax
6

7
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
8 9 10 11 12

function builder() {
  return new WasmModuleBuilder;
}

13
function assertCompileError(bytes, msg) {
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  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);
29 30
}

31 32
// default imports to {} so we get LinkError by default, thus allowing us to
// distinguish the TypeError we want to catch
33
function assertTypeError(bytes, imports = {}, msg) {
34
  assertInstantiateError(TypeError, bytes, imports, msg);
35 36
}

37
function assertLinkError(bytes, imports, msg) {
38
  assertInstantiateError(WebAssembly.LinkError, bytes, imports, msg);
39 40
}

41
function assertConversionError(bytes, imports, msg) {
42 43 44
  let instance =
      new WebAssembly.Instance(new WebAssembly.Module(bytes), imports);
  assertThrows(() => instance.exports.run(), TypeError, msg);
45 46 47
}

(function TestDecodingError() {
48
  print(arguments.callee.name);
49 50
  assertCompileError(bytes(), 'BufferSource argument is empty');
  assertCompileError(bytes('X'), 'expected 4 bytes, fell off end @+0');
51
  assertCompileError(
52 53
      bytes('\0x00asm'),
      'expected magic word 00 61 73 6d, found 00 78 30 30 @+0');
54 55 56
})();

(function TestValidationError() {
57
  print(arguments.callee.name);
58
  let error = msg => 'Compiling function #0 failed: ' + msg;
59
  let f_error = msg => 'Compiling function #0:"f" failed: ' + msg;
60 61 62 63 64 65 66 67 68 69 70 71 72
  assertCompileError(
      (function build() {
        let b = builder();
        b.addType(kSig_v_v);
        // Use explicit section because the builder would automatically emit
        // e.g. locals declarations.
        // 1 function with type 0.
        b.addExplicitSection([kFunctionSectionCode, 2, 1, 0]);
        // 1 function body with length 0.
        b.addExplicitSection([kCodeSectionCode, 2, 1, 0]);
        return b.toBuffer();
      })(),
      error('expected local decls count @+22'));
73
  assertCompileError(
74
      builder().addFunction('f', kSig_i_v).end().toBuffer(),
75
      f_error('function body must end with "end" opcode @+24'));
76 77 78
  assertCompileError(
      builder().addFunction('f', kSig_i_v).addBody([kExprReturn])
          .end().toBuffer(),
79
      f_error('expected 1 elements on the stack for return, found 0 @+24'));
80
  assertCompileError(builder().addFunction('f', kSig_v_v).addBody([
81
    kExprLocalGet, 0
82
  ]).end().toBuffer(), f_error('invalid local index: 0 @+24'));
83
  assertCompileError(
84 85
      builder().addStart(0).toBuffer(),
      'start function index 0 out of bounds (0 entries) @+10');
86 87
})();

88 89 90 91 92 93
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;
}

94
(function TestTypeError() {
95
  print(arguments.callee.name);
96 97 98 99 100
  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);
101 102

  b = builder();
103 104
  b.addImportedGlobal('foo', 'bar', kWasmI32);
  assertTypeError(b.toBuffer(), {}, msg);
105 106

  b = builder();
107 108
  b.addImportedMemory('foo', 'bar');
  assertTypeError(b.toBuffer(), {}, msg);
109 110 111
})();

(function TestLinkingError() {
112
  print(arguments.callee.name);
113
  let b;
114
  let msg;
115

116
  b = builder();
117 118 119
  msg = import_error(0, 'foo', 'bar', 'function import requires a callable');
  b.addImport('foo', 'bar', kSig_v_v);
  assertLinkError(b.toBuffer(), {foo: {}}, msg);
120
  b = builder();
121 122
  b.addImport('foo', 'bar', kSig_v_v);
  assertLinkError(b.toBuffer(), {foo: {bar: 9}}, msg);
123

124
  b = builder();
125 126
  msg = import_error(
      0, 'foo', 'bar',
127 128
      'global import must be a number, valid Wasm reference, '
        + 'or WebAssembly.Global object');
129 130
  b.addImportedGlobal('foo', 'bar', kWasmI32);
  assertLinkError(b.toBuffer(), {foo: {}}, msg);
131
  b = builder();
132 133
  b.addImportedGlobal('foo', 'bar', kWasmI32);
  assertLinkError(b.toBuffer(), {foo: {bar: ''}}, msg);
134
  b = builder();
135 136
  b.addImportedGlobal('foo', 'bar', kWasmI32);
  assertLinkError(b.toBuffer(), {foo: {bar: () => 9}}, msg);
137 138

  b = builder();
139 140 141 142
  msg = import_error(
      0, 'foo', 'bar', 'memory import must be a WebAssembly.Memory object');
  b.addImportedMemory('foo', 'bar');
  assertLinkError(b.toBuffer(), {foo: {}}, msg);
143
  b = builder();
144
  b.addImportedMemory('foo', 'bar', 1);
145 146
  assertLinkError(
      b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}},
147
      msg);
148
})();
149

150 151 152 153 154 155 156 157 158 159 160 161 162
(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);
163 164
})();

165 166 167 168 169 170
(function TestUnreachableInStart() {
  print(arguments.callee.name);

  let b = builder().addFunction("start", kSig_v_v).addBody(
     [kExprUnreachable]).end().addStart(0);
  assertTraps(kTrapUnreachable, () => b.instantiate());
171 172
})();

173
(function InternalDebugTrace() {
174
  print(arguments.callee.name);
175 176 177 178
  var builder = new WasmModuleBuilder();
  var sig = builder.addType(kSig_i_dd);
  builder.addImport("mod", "func", sig);
  builder.addFunction("main", sig)
179
    .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprCallFunction, 0])
180
    .exportAs("main");
181 182 183 184 185 186 187
  var main = builder.instantiate({
    mod: {
      func: ()=>{%DebugTrace();}
    }
  }).exports.main;
  main();
})();
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

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