domenic / promises-unwrapping

The ES6 promises spec, as per September 2013 TC39 meeting
1.23k stars 94 forks source link

What happens if ArrayCreate throws in Promise.all? #90

Closed bzbarsky closed 10 years ago

bzbarsky commented 10 years ago

Per es6 spec ArrayCreate apparently can't throw, but in practice it can due to OOM. Should this do the normal OOM thing with an uncatchable exception, or try to somehow detect the situation and reject the promise (whatever that means if you're OOM....)?

domenic commented 10 years ago

Yeah I can't imagine trying to transform this into a rejection would be useful in any way. Especially since there's not really a counterpart "uncatchable rejection."

What would you suggest speccing for this, if anything? I'm not familiar with how to spec impossible-but-actually-possible scenarios :)

bzbarsky commented 10 years ago

The way we'll be implementing this in Gecko for now is that if you call Promise.all and you can't allocate an array, we report the OOM to the console and abort execution of your script.

The way V8/Blink will implement it is by crashing the entire content process.

Note that these are observably different behaviors from the point of view of the web page (e.g. in Blink you can never run any code on the page after the allocation failure but in Gecko you can).

I have no idea how to spec this in a way that's acceptable to everyone, honestly.

annevk commented 10 years ago

Specifications don't deal with OOM generally. HTML says "User agents may impose implementation-specific limits on otherwise unconstrained inputs, e.g. to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations."

allenwb commented 10 years ago

On Jan 22, 2014, at 3:17 PM, Boris Zbarsky wrote:

Per es6 spec ArrayCreate apparently can't throw, but in practice it can due to OOM. Should this do the normal OOM thing with an uncatchable exception, or try to somehow detect the situation and reject the promise (whatever that means if you're OOM...

ArrayCreate can throw for an invalid length, but Promise.all passes a length of 0 so that isn't going to happen

In general, the ES6 spec. doesn't check for OOM on ordinary object allocations. If you can't allocate a basic object then there probably isn't much you can continue. ArrayBuffer on the other hand is specified to explicitly check for OOM and throw. Presumably the allocation of a huge block could fail and still leave plenty of space available for normal execution.

By the spec, ArrayCreate allocates a sparse array, even when a length is provided, so it is like a ordinary object allocation. But an implementation might use the length to preallocate space for a dense array. In that case it should probably recoverably fail on OOM just like ArrayBuffer. Since ArrayCreate is already specified to possibly throw (bad length) callers to it should be prepared for it to fail with an exception.

Allen

erights commented 10 years ago

There are serious security issues with continuing execution within a vat after oom https://code.google.com/p/google-caja/issues/detail?id=460. Crashing the vat is best, and corresponds well to why the Erlang failure model works so well. We should think about specifying oom as well as took-too-long in ES7.

On Wed, Jan 22, 2014 at 4:23 PM, Allen Wirfs-Brock <notifications@github.com

wrote:

On Jan 22, 2014, at 3:17 PM, Boris Zbarsky wrote:

Per es6 spec ArrayCreate apparently can't throw, but in practice it can due to OOM. Should this do the normal OOM thing with an uncatchable exception, or try to somehow detect the situation and reject the promise (whatever that means if you're OOM...

ArrayCreate can throw for an invalid length, but Promise.All pass a length of 0 so that isn't going to happen

In general, the ESW6 spec. doesn't check for OOM on ordinary object allocations. If you can allocate a basic object then there probably isn't much you can continue. ArrayBuffer on the other hand is specified to explicitly check for OOM and throw. Presumably the allocation of a huge block could fail and still leave plenty of space available for normal execution.

By the spec, ArrayCreate allocates a space array, even when a length is provided, so it is like a ordinary object allocation. But an implementation might use the length to preallocate space for a dense array. In that case it should probably recoverably fail on OOM just like ArrayBuffer. Since ArrayCreate is already specified to possibly throw (bad length) callers to it should be prepared for it to fail with an exception.

Allen

— Reply to this email directly or view it on GitHubhttps://github.com/domenic/promises-unwrapping/issues/90#issuecomment-33085129 .

Text by me above is hereby placed in the public domain

Cheers, --MarkM

domenic commented 10 years ago

What is our conclusion here? That there's a missing ReturnIfAbrupt after ArrayCreate usage? Sounds like an easy fix.

allenwb commented 10 years ago

It's probably not needed. Because the parameter to the ArrayCreate is 0, it is like an ordinary object allocation and is never expected to have a recoverable OOM error. In general the ES6 spec doesn't try to deal with non-recoverable OOM errors that presumably could occur pretty much anywhere.

domenic commented 10 years ago

OK, sounds good; thanks Allen.