When creating `new Error` and reading `e.stack` there is consistently (in certain situations) a second or third frame missing. Test case: https://codepen.io/Krinkle/pen/jOoggZw In Firefox, Chrome, the raw stack is: ``` [0] sourceFromStacktrace [1] QUnit.stack [2] exampleBar [3] exampleFoo [4] exampleMain [5] makeFakeFailure ``` In Safari, one of the intermediary frame has excluded. ``` [0] sourceFromStacktrace [1] exampleBar [2] exampleFoo [3] exampleMain [4] makeFakeFailure ``` This is problematic because in diagnostic tools and test frameworks like QUnit, a function like QUnit.stack() will often omit the first few frames for developer convenience, hiding its known internal offset. In the case of the above, QUnit would strip the first 2 frames when QUnit.stack is directly directly, or possibly more when passed an offset for additional wrapper functions. The practical impact is that slice(2) ends up removing part of the user's own stack. Thus misleading them into thinking there is an error thrown by exampleFoo, when actually it caused deeper down in exampleBar. I suspect this may be some kind of JIT operation combined with a failure to retain/restore the stack trace. Or perhaps a privacy hueristic misfiring. However, I've been unable to reproduce with an inline script tag, only with an external script. The above CodePen copies the two functions from qunit.js ("live") and embeds them directly ("reduced"). The issue does not happen in that case. Safari Version 17.5 (18618.2.12.111.5, 18618)
Keywords: stacktrace, stack trace, callstack, call stack, exception. Possibly related: https://bugs.webkit.org/show_bug.cgi?id=70605
Created attachment 471806 [details] Runtime Error.stack differs from Web Inspector showing the correct stack
Created attachment 471807 [details] Caller context
Created attachment 471808 [details] Caller-caller context
Created attachment 471809 [details] Firefox comparison for reference
This is the correct behavior because ECMAScript spec defines tail-calls, and QUnit.stack is taking tail-call form (strict mode, and calling sourceFromStacktrace in tail-call position). So, Firefox and Chrome behaviors are wrong in terms of the spec.
You can ask to Firefox / Chrome to implement tail-call as spec requires, and then QUnit implementation should be fixed.
Thanks, I was able to finally reproduce this in isolation by changing: ``` var QUnit_reduced = { stack: function (offset) { offset = (offset || 0) + 2; return sourceFromStacktrace(offset); } } ``` to ``` var QUnit_reduced = { stack: function (offset) { 'use strict'; offset = (offset || 0) + 2; return sourceFromStacktrace(offset); } } ``` Related reading: * https://262.ecma-international.org/11.0/#sec-function-calls-runtime-semantics-evaluation - Defining IsInTailPosition * https://262.ecma-international.org/11.0/#sec-evaluatecall - tailCall/tailPosition dictating "as if it has already returned" * https://stackoverflow.com/a/54721813/319266 - Tail Calls introduced in ES6 and shipped by Safari, but defacto JSC/WebKit-only at this point. * https://github.com/tc39/proposal-error-stacks/ - seeking to standardise Error.stack * https://github.com/tc39/proposal-error-stacks/issues/23