v8/test/mjsunit/wasm/stack.js
Benedikt Meurer c0ee8f905b [wasm][inspector] Don't use Script::source_url to store URL.
The `Script::source_url` field holds the value of the magic
`//# sourceURL` comment if found, and the `Script::name` field is
supposed to hold the actual name of the resource (as provided by
the embedder ideally), in case of Chromium that's supposed to be
the URL (in case of Node.js it's often the local path).

Using `source_url` worked by chance so far, but for loading DWARF
symbol files correctly we need the initiator (which we pick from
the embedderName of the Script as reported to DevTools). More
importantly, the partial handling of `//# sourceURL` in V8 is a
layering violation and causes trouble in DevTools, i.e. when users
put relative paths here. So as part of refactoring and correctifying
the handling of `//# sourceURL`, we need to make sure that the embedder
provided name (the URL in case of Chromium) is always stored in the
`Script::name` field.

Bug: chromium:1183990, chromium:974543, chromium:1174507
Change-Id: I32e11def2b9b52be11bd2e0e64a2ab6bdcf5e52d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2773584
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73536}
2021-03-19 12:19:13 +00:00

185 lines
6.6 KiB
JavaScript

// 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 --no-force-slow-path
load("test/mjsunit/wasm/wasm-module-builder.js");
// The stack trace contains file path, only keep "stack.js".
function stripPath(s) {
return s.replace(/[^ (]*stack\.js/g, "stack.js");
}
function verifyStack(frames, expected) {
assertEquals(expected.length, frames.length, "number of frames mismatch");
expected.forEach(function(exp, i) {
assertEquals(exp[1], frames[i].getFunctionName(),
"["+i+"].getFunctionName()");
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]) {
toString = "<anonymous>:wasm-function[" + exp[6] + "]:" + exp[5];
if (exp[1] !== null) toString = exp[1] + " (" + toString + ")";
} else {
toString = exp[4] + ":" + exp[2] + ":";
}
assertContains(toString, frames[i].toString(), "["+i+"].toString()");
});
}
var stack;
function STACK() {
var e = new Error();
stack = e.stack;
}
var builder = new WasmModuleBuilder();
builder.addMemory(0, 1, false);
builder.addImport("mod", "func", kSig_v_v);
builder.addFunction("main", kSig_v_v)
.addBody([kExprCallFunction, 0])
.exportAs("main");
builder.addFunction("exec_unreachable", kSig_v_v)
.addBody([kExprUnreachable])
.exportAs("exec_unreachable");
// Make this function unnamed, just to test also this case.
var mem_oob_func = builder.addFunction(undefined, kSig_i_v)
// Access the memory at offset -1, to provoke a trap.
.addBody([kExprI32Const, 0x7f, kExprI32LoadMem8S, 0, 0])
.exportAs("mem_out_of_bounds");
// Call the mem_out_of_bounds function, in order to have two wasm stack frames.
builder.addFunction("call_mem_out_of_bounds", kSig_i_v)
.addBody([kExprCallFunction, mem_oob_func.index])
.exportAs("call_mem_out_of_bounds");
var module = builder.instantiate({mod: {func: STACK}});
(function testSimpleStack() {
var expected_string = 'Error\n' +
// The line numbers below will change as this test gains / loses lines..
' 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'; // --
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() {
module.exports.main();
verifyStack(stack, [
// isWasm function line pos file offset funcIndex
[ false, "STACK", 38, 0, "stack.js"],
[ true, "main", 1, 0x86, "wasm://wasm/7168ab72", '0x86', 1],
[ false, "testStackFrames", 88, 0, "stack.js"],
[ false, null, 97, 0, "stack.js"]
]);
})();
(function testWasmUnreachable() {
try {
module.exports.exec_unreachable();
fail("expected wasm exception");
} catch (e) {
assertContains("unreachable", e.message);
verifyStack(e.stack, [
// isWasm function line pos file offset funcIndex
[ true, "exec_unreachable", 1, 0x8b, "wasm://wasm/7168ab72", '0x8b', 2],
[ false, "testWasmUnreachable", 101, 0, "stack.js"],
[ false, null, 112, 0, "stack.js"]
]);
}
})();
(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, [
// isWasm function line pos file offset funcIndex
[ true, "mem_out_of_bounds", 1, 0x91, "wasm://wasm/7168ab72", '0x91', 3],
[ true, "call_mem_out_of_bounds", 1, 0x97, "wasm://wasm/7168ab72", '0x97', 4],
[ false, "testWasmMemOutOfBounds", 116, 0, "stack.js"],
[ false, null, 128, 0, "stack.js"]
]);
}
})();
(function testStackOverflow() {
print("testStackOverflow");
var builder = new WasmModuleBuilder();
var sig_index = builder.addType(kSig_v_v);
builder.addFunction("recursion", sig_index)
.addBody([
kExprI32Const, 0,
kExprCallIndirect, sig_index, kTableZero
])
.exportFunc();
builder.appendToTable([0]);
try {
builder.instantiate().exports.recursion();
fail("expected wasm exception");
} catch (e) {
assertEquals("Maximum call stack size exceeded", e.message, "trap reason");
assertTrue(e.stack.length >= 4, "expected at least 4 stack entries");
verifyStack(e.stack.splice(0, 4), [
// isWasm function line pos file offset funcIndex
[ true, "recursion", 1, 0x34, "wasm://wasm/80a35e5a", '0x34', 0],
[ true, "recursion", 1, 0x37, "wasm://wasm/80a35e5a", '0x37', 0],
[ true, "recursion", 1, 0x37, "wasm://wasm/80a35e5a", '0x37', 0],
[ true, "recursion", 1, 0x37, "wasm://wasm/80a35e5a", '0x37', 0]
]);
}
})();
(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');
let hexOffset = '0x' + (unreachable_pos + 0x25).toString(16);
verifyStack(e.stack, [
// isWasm function line pos file offset funcIndex
[ true, 'main', 1, unreachable_pos + 0x25, 'wasm://wasm/000600e6', hexOffset, 0],
[ false, 'testBigOffset', 172, 0, 'stack.js'],
[ false, null, 184, 0, 'stack.js']
]);
}
})();