Error stack strawman

Mark S. Miller erights at
Wed Feb 24 21:30:17 UTC 2016

Huh, weird. From the discussions that led to <> being
proposed and the discussion on that issue, for me to take a consistent
position, I must sadly concede the following:

We allowed a grossly leaky api (the RegExp statics, which leak non-local
information from RegExp instances <>)
to be proposed for standardization as "normative optional", i.e., Annex B,
and deletable. This way, and environment that deletes it still leaves a
conforming system in its wake. Many people think they want error.stack
because it seems to do something on all the browsers -- though their
behaviors are tremendously different from each other. Nevertheless,
whatever behavior we specify for getStackString, we could likewise spec a
normative optional and deletable Error.prototype.stack accessor property,
like Firefox's[1]. As with makeWeakRef and the leaky RegExp statics, we
could specify the getter of this accessor only to work on Error objects
from the same realm[2]. Since errors inherit from the Error.prototype of
their own realm anyway, this does not impede normal usage. We need to
impose the same restriction on getStack and getStackString anyway, for the
same reasons.

FF demonstrates that it is already web compatible to provide error.stack
only by providing a deletable Error.prototype.stack accessor.

On FF, my polyfill <> makes use
of the fact that Error.prototype.stack is an accessor, both to censor the
property on initialization, be deleting it, and to reserve for itself the
ability to inspect stacks, by utilizing the getter it took away. That is
how it implements getStack without providing ambient access to the stack.

[1] For some reason the FF stack accessor has both getter and setter. I
don't see any reason for a setter.
[2] This solves only one of the cross-realm issue with stacks. It does
nothing to address worries about cross-realm stacks.

On Wed, Feb 24, 2016 at 12:37 PM, Mark S. Miller <erights at> wrote:

> On Wed, Feb 24, 2016 at 11:40 AM, Steve Fink <sphink at> wrote:
>> On 02/19/2016 01:26 AM, Andreas Rossberg wrote:
>> On 19 February 2016 at 03:13, Gary Guo <nbdd0121 at> wrote:
>> If we are not going to indicate tail call some way, debugging might be
>>> extremely difficult, and the stack result might be making no sense at all.
>> A tail call is a jump. Just like other jumps, you shouldn't expect their
>> history to be visible in the continuation (which is what a stack trace
>> represents). I agree that JS programmers might be surprised, and will have
>> to relearn what they know. But wrt to debugging the situation is the same
>> as for loops: you can't inspect their history either. (And functional
>> programmers in fact see loops as just an ugly way to express self tail
>> recursion. :) )
>> To be even more pedantic: the stack trace isn't "the" continuation, it is
>> one possible continuation. Other continuations are possible if you throw an
>> exception. I guess you could say the stack trace plus the code allows you
>> to statically derive the full set of possible continuations.
>> But I agree that it's worthwhile to remember the difference, since what
>> is being requested for stacks really *is* a history, not a continuation.
>> For example, it is desireable to encode "long stacks" or "async stacks" or
>> whatever they're being called these days, where eg for an event handler you
>> get the stack trace at the point the handler was installed. That is not a
>> continuation, that is history. I would be very wary of mandating that full
>> history be preserved, since it's easy for it to prevent optimizations or
>> inadvertently leak details of the underlying implementation (tail calls,
>> inlining, captured environments).
>> Does it work to specify something like "if and only if the information is
>> available, it shall be encoded like this:..."? That can still leak
>> information if not handled carefully, but at least it doesn't inhibit
>> optimizations.
>> For a wild handwavy example of an information leak: say you do not
>> include inlined calls in stack frames, and you only inline a call after the
>> 10th invocation. Further assume that you self-host some JS feature. The
>> caller can now learn something about how many times that self-hosted
>> feature has been used. That feature might happen to be Math.something used
>> only for processing non-latin1 characters in a password, or more likely
>> just some feature used only if you are logged into a certain site. (Perhaps
>> Error.stack is already specced to avoid this, by requiring all frames to be
>> included whether inlined or not? Sorry, I don't know anything about it; I'm
>> just posting to ask the question about what specifying stack formats
>> encompasses.)
> This information leak is not specific to tail-call variance. It is a
> problem with the whole error.stack interface <
> Like makeWeakRef <>, that is why
> the getStack and getStackString functions won't be generally available to
> confined code, but must instead be virtualizable or deniable. Starting with
> KeyKOS, capability practitioners refer to this category as "closely held",
> as opposed to "ambient". *Everything* in the ES6 standard itself is
> ambient, since we postponed spec'ing anything that needs to be closely
> held. Now is that time <>.
> Again, as with makeWeakRef, by treating getStack and getStackString as
> closely held, it is also less damaging[1] for them to leak implementation
> non-determinacy that may carry side channels or covert channels.
> [1] It is less damaging when the leakage is limited to intra-realm, since
> one realm is not in a position to police another. For getStack and
> getStackString, this is yet another reason we need to think hard about
> cross-realm stacks. I, for one, have not yet done so.
> --
>     Cheers,
>     --MarkM

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list