RESOLVED FIXED Bug 179826
WebAssembly JS API: throw when a promise can't be created
https://bugs.webkit.org/show_bug.cgi?id=179826
Summary WebAssembly JS API: throw when a promise can't be created
JF Bastien
Reported 2017-11-17 10:03:39 PST
Failure *in* a promise causes rejection, but failure to create a promise (because of stack overflow) isn't really spec'd (as all stack things JS). This applies to WebAssembly.compile and WebAssembly.instantiate. Dan's current proposal says: https://littledan.github.io/spec/document/js-api/index.html#stack-overflow Whenever a stack overflow occurs in WebAssembly code, the same class of exception is thrown as for a stack overflow in JavaScript. The particular exception here is implementation-defined in both cases. Note: ECMAScript doesn’t specify any sort of behavior on stack overflow; implementations have been observed to throw RangeError, InternalError or Error. Any is valid here. This is for general stack overflow within WebAssembly, not specifically for promise creation within JavaScript, but it seems like a stack overflow in promise creation should follow the same rule instead of, say, swallowing the overflow and returning undefined.
Attachments
patch (7.04 KB, patch)
2017-11-17 10:07 PST, JF Bastien
no flags
patch (7.11 KB, patch)
2017-11-17 10:09 PST, JF Bastien
mark.lam: review-
patch (11.25 KB, patch)
2017-11-17 11:25 PST, JF Bastien
mark.lam: review+
patch (11.20 KB, patch)
2017-11-17 13:12 PST, JF Bastien
no flags
JF Bastien
Comment 1 2017-11-17 10:07:34 PST
JF Bastien
Comment 2 2017-11-17 10:08:13 PST
JF Bastien
Comment 3 2017-11-17 10:09:39 PST
Created attachment 327191 [details] patch Missing radar in ChangeLog.
Mark Lam
Comment 4 2017-11-17 10:24:21 PST
Comment on attachment 327191 [details] patch View in context: https://bugs.webkit.org/attachment.cgi?id=327191&action=review I suspect once you've changed these to using ThrowScopes, some jsc tests will start failing (due to missing exception checks). Please change these and retest. > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:97 > auto scope = DECLARE_CATCH_SCOPE(vm); > auto* globalObject = exec->lexicalGlobalObject(); > > - JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, globalObject); > - CLEAR_AND_RETURN_IF_EXCEPTION(scope, encodedJSValue()); > + JSPromiseDeferred* promise = createPromise(vm, exec, globalObject); > + RETURN_IF_EXCEPTION(scope, encodedJSValue()); This does not look right. Being in a CatchScope means we should never return with an exception. I think you'll want to change that DECLARE_CATCH_SCOPE to DECLARE_THROW_SCOPE. > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:199 > auto scope = DECLARE_CATCH_SCOPE(vm); > - > - JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject()); > - CLEAR_AND_RETURN_IF_EXCEPTION(scope, encodedJSValue()); > + auto* globalObject = exec->lexicalGlobalObject(); > + > + JSPromiseDeferred* promise = createPromise(vm, exec, globalObject); > + RETURN_IF_EXCEPTION(scope, encodedJSValue()); Ditto. You should be using a DECLARE_THROW_SCOPE here.
JF Bastien
Comment 5 2017-11-17 11:25:48 PST
Created attachment 327201 [details] patch Updated as discussed offline with mlam.
Mark Lam
Comment 6 2017-11-17 11:41:16 PST
Comment on attachment 327201 [details] patch View in context: https://bugs.webkit.org/attachment.cgi?id=327201&action=review From the missing clearException()s in this patch, I realized that the CatchScope destructor is missing an ASSERT(!vm.exception()). If that causes more failures to manifest, you can file a bug to add that assert and fix those assertion failures later. It also looks like we may also be missing some test cases: 1. we need one that throws an exception and trigger the rejection immediately (which should fail that assertion in the CatchScope destructor, if not earlier in the reject function). 2. we need one that throws an exception in the reject callback (which should also fail that assertion in the CatchScope destructor). > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:101 > + if (UNLIKELY(catchScope.exception())) > + reject(exec, catchScope, promise); This only detects the exception, but does not clear it. You should also clear the exception using catchScope.clearException() before calling the reject code. Hmmm, that also makes me wonder what happens if the reject callback throws an exception? If it does, I presume we should eat it too just like we do for async calls to the reject callback. That means you'll also need to call catchScope.clearException() after the call to reject(). > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:181 > + if (UNLIKELY(scope.exception())) > return reject(exec, scope, promise); Ditto. You'll need to clearException() before and after the reject function().
JF Bastien
Comment 7 2017-11-17 12:49:27 PST
(In reply to Mark Lam from comment #6) > Comment on attachment 327201 [details] > patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=327201&action=review > > From the missing clearException()s in this patch, I realized that the > CatchScope destructor is missing an ASSERT(!vm.exception()). If that causes > more failures to manifest, you can file a bug to add that assert and fix > those assertion failures later. That fails miserably :( Filed #179836. > It also looks like we may also be missing > some test cases: > 1. we need one that throws an exception and trigger the rejection > immediately (which should fail that assertion in the CatchScope destructor, > if not earlier in the reject function). > 2. we need one that throws an exception in the reject callback (which should > also fail that assertion in the CatchScope destructor). > > > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:101 > > + if (UNLIKELY(catchScope.exception())) > > + reject(exec, catchScope, promise); > > This only detects the exception, but does not clear it. You should also > clear the exception using catchScope.clearException() before calling the > reject code. > > Hmmm, that also makes me wonder what happens if the reject callback throws > an exception? If it does, I presume we should eat it too just like we do > for async calls to the reject callback. That means you'll also need to call > catchScope.clearException() after the call to reject(). > > > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:181 > > + if (UNLIKELY(scope.exception())) > > return reject(exec, scope, promise); > > Ditto. You'll need to clearException() before and after the reject > function(). It's handled in the helper: static void reject(ExecState* exec, CatchScope& catchScope, JSPromiseDeferred* promise) { Exception* exception = catchScope.exception(); ASSERT(exception); catchScope.clearException(); promise->reject(exec, exception->value()); CLEAR_AND_RETURN_IF_EXCEPTION(catchScope, void()); }
Mark Lam
Comment 8 2017-11-17 12:56:32 PST
Comment on attachment 327201 [details] patch View in context: https://bugs.webkit.org/attachment.cgi?id=327201&action=review r=me with the remaining fix. > Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp:205 > + RETURN_IF_EXCEPTION(catchScope, encodedJSValue()); This is still wrong. For CatchScope, you should use clearException() here and just return JSValue::encode(promise->promise()) below. The client of this function would expect to get the promise even if it's rejected, right? In any case, returning encodedJSValue() means returning a nullptr, and this will cause crashes for when there are no exceptions. You should never exit a CatchScope with a pending exception.
JF Bastien
Comment 9 2017-11-17 13:12:33 PST
WebKit Commit Bot
Comment 10 2017-11-17 13:56:37 PST
The commit-queue encountered the following flaky tests while processing attachment 327220 [details]: http/tests/xmlhttprequest/redirect-cross-origin-tripmine.html bug 179840 (authors: ap@webkit.org and rniwa@webkit.org) The commit-queue is continuing to process your patch.
WebKit Commit Bot
Comment 11 2017-11-17 13:57:12 PST
Comment on attachment 327220 [details] patch Clearing flags on attachment: 327220 Committed r224985: <https://trac.webkit.org/changeset/224985>
WebKit Commit Bot
Comment 12 2017-11-17 13:57:14 PST
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.