stack.js 6.27 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 --no-force-slow-path
6

7
load("test/mjsunit/wasm/wasm-module-builder.js");
8 9 10 11 12 13

// The stack trace contains file path, only keep "stack.js".
function stripPath(s) {
  return s.replace(/[^ (]*stack\.js/g, "stack.js");
}

14 15 16
function verifyStack(frames, expected) {
  assertEquals(expected.length, frames.length, "number of frames mismatch");
  expected.forEach(function(exp, i) {
clemensh's avatar
clemensh committed
17 18
    assertEquals(exp[1], frames[i].getFunctionName(),
        "["+i+"].getFunctionName()");
19 20 21 22 23 24 25
    assertEquals(exp[2], frames[i].getLineNumber(), "["+i+"].getLineNumber()");
    if (exp[0])
      assertEquals(exp[3], frames[i].getPosition(),
          "["+i+"].getPosition()");
    assertContains(exp[4], frames[i].getFileName(), "["+i+"].getFileName()");
    var toString;
    if (exp[0]) {
26
      toString = "<anonymous>:wasm-function[" + exp[6] + "]:" + exp[5];
27
      if (exp[1] !== null) toString = exp[1] + " (" + toString + ")";
28 29 30 31
    } else {
      toString = exp[4] + ":" + exp[2] + ":";
    }
    assertContains(toString, frames[i].toString(), "["+i+"].toString()");
32 33 34 35
  });
}


36 37 38 39 40 41
var stack;
function STACK() {
  var e = new Error();
  stack = e.stack;
}

42 43
var builder = new WasmModuleBuilder();

44 45
builder.addMemory(0, 1, false);

46
builder.addImport("mod", "func", kSig_v_v);
47

48
builder.addFunction("main", kSig_v_v)
49
  .addBody([kExprCallFunction, 0])
50
  .exportAs("main");
51

52
builder.addFunction("exec_unreachable", kSig_v_v)
53 54 55
  .addBody([kExprUnreachable])
  .exportAs("exec_unreachable");

56
// Make this function unnamed, just to test also this case.
57
var mem_oob_func = builder.addFunction(undefined, kSig_i_v)
58
  // Access the memory at offset -1, to provoke a trap.
59
  .addBody([kExprI32Const, 0x7f, kExprI32LoadMem8S, 0, 0])
60 61
  .exportAs("mem_out_of_bounds");

62
// Call the mem_out_of_bounds function, in order to have two wasm stack frames.
63 64
builder.addFunction("call_mem_out_of_bounds", kSig_i_v)
  .addBody([kExprCallFunction, mem_oob_func.index])
65 66
  .exportAs("call_mem_out_of_bounds");

67
var module = builder.instantiate({mod: {func: STACK}});
68

69
(function testSimpleStack() {
70 71
  var expected_string = 'Error\n' +
      // The line numbers below will change as this test gains / loses lines..
72 73 74 75
      '    at STACK (stack.js:38:11)\n' +                   // --
      '    at main (<anonymous>:wasm-function[1]:0x86)\n' + // --
      '    at testSimpleStack (stack.js:77:18)\n' +         // --
      '    at stack.js:79:3';                               // --
76 77 78 79 80 81 82 83 84 85 86 87

  module.exports.main();
  assertEquals(expected_string, stripPath(stack));
})();

// For the remaining tests, collect the Callsite objects instead of just a
// string:
Error.prepareStackTrace = function(error, frames) {
  return frames;
};

(function testStackFrames() {
88
  module.exports.main();
89 90

  verifyStack(stack, [
91
      // isWasm           function   line  pos        file  offset funcIndex
92
      [   false,           "STACK",    38,   0, "stack.js"],
93
      [    true,            "main",     0,   1,       null, '0x86',        1],
94 95
      [   false, "testStackFrames",    88,   0, "stack.js"],
      [   false,              null,    97,   0, "stack.js"]
96
  ]);
97
})();
98 99 100 101 102 103 104 105

(function testWasmUnreachable() {
  try {
    module.exports.exec_unreachable();
    fail("expected wasm exception");
  } catch (e) {
    assertContains("unreachable", e.message);
    verifyStack(e.stack, [
106 107
        // isWasm               function   line  pos        file  offset funcIndex
        [    true,    "exec_unreachable",    0,    1,       null, '0x8b',        2],
108 109
        [   false, "testWasmUnreachable",  101,    0, "stack.js"],
        [   false,                  null,  112,    0, "stack.js"]
110 111 112 113 114 115 116 117 118 119 120
    ]);
  }
})();

(function testWasmMemOutOfBounds() {
  try {
    module.exports.call_mem_out_of_bounds();
    fail("expected wasm exception");
  } catch (e) {
    assertContains("out of bounds", e.message);
    verifyStack(e.stack, [
121
        // isWasm                  function   line  pos        file  offset funcIndex
122
        [    true,      "mem_out_of_bounds",     0,   3,       null, '0x91',        3],
123
        [    true, "call_mem_out_of_bounds",     0,   1,       null, '0x97',        4],
124 125
        [   false, "testWasmMemOutOfBounds",   116,   0, "stack.js"],
        [   false,                     null,   128,   0, "stack.js"]
126 127 128
    ]);
  }
})();
129 130 131 132 133 134 135 136 137

(function testStackOverflow() {
  print("testStackOverflow");
  var builder = new WasmModuleBuilder();

  var sig_index = builder.addType(kSig_v_v);
  builder.addFunction("recursion", sig_index)
    .addBody([
      kExprI32Const, 0,
138
      kExprCallIndirect, sig_index, kTableZero
139
    ])
140
    .exportFunc();
141 142 143 144 145 146 147
  builder.appendToTable([0]);

  try {
    builder.instantiate().exports.recursion();
    fail("expected wasm exception");
  } catch (e) {
    assertEquals("Maximum call stack size exceeded", e.message, "trap reason");
148 149
    assertTrue(e.stack.length >= 4, "expected at least 4 stack entries");
    verifyStack(e.stack.splice(0, 4), [
150 151 152 153 154
        // isWasm     function  line  pos  file  offset funcIndex
        [    true, "recursion",    0,   0, null, '0x34',        0],
        [    true, "recursion",    0,   3, null, '0x37',        0],
        [    true, "recursion",    0,   3, null, '0x37',        0],
        [    true, "recursion",    0,   3, null, '0x37',        0]
155
    ]);
156 157
  }
})();
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

(function testBigOffset() {
  print('testBigOffset');
  var builder = new WasmModuleBuilder();

  let body = [kExprI32Const, 0, kExprI32Add];
  while (body.length <= 65536) body = body.concat(body);
  body.unshift(kExprI32Const, 0);
  body.push(kExprUnreachable);
  let unreachable_pos = body.length - 1;

  builder.addFunction('main', kSig_v_v).addBody(body).exportFunc();

  try {
    builder.instantiate().exports.main();
    fail('expected wasm exception');
  } catch (e) {
    assertEquals('unreachable', e.message, 'trap reason');
176
    let hexOffset = '0x' + (unreachable_pos + 0x25).toString(16);
177
    verifyStack(e.stack, [
178 179 180 181
      // isWasm         function line                  pos        file     offset funcIndex
      [    true,          'main',   0, unreachable_pos + 1,       null, hexOffset,        0],
      [   false, 'testBigOffset', 172,                   0, 'stack.js'],
      [   false,            null, 184,                   0, 'stack.js']
182 183 184
    ]);
  }
})();