|  | // 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",     0,   1,       null, '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",    0,    1,       null, '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",     0,   3,       null, '0x91',        3], | 
|  | [    true, "call_mem_out_of_bounds",     0,   1,       null, '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",    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] | 
|  | ]); | 
|  | } | 
|  | })(); | 
|  |  | 
|  | (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',   0, unreachable_pos + 1,       null, hexOffset,        0], | 
|  | [   false, 'testBigOffset', 172,                   0, 'stack.js'], | 
|  | [   false,            null, 184,                   0, 'stack.js'] | 
|  | ]); | 
|  | } | 
|  | })(); |