Bug 1494518 - Do not pass non-PromiseObject to JSRuntime::enqueuePromiseJob. r=till
authorTooru Fujisawa <arai_a@mac.com>
Fri, 28 Sep 2018 00:06:51 +0900
changeset 438636 e7d5eb0d44a7ee8b6d53d91d96986af873fa16af
parent 438627 cb1bd4097d6bf9ad61c6f4ff146ba193bf370193
child 438637 5d60b68a0a426e3c316435e315ddddf35f3aea20
push id34730
push useraciure@mozilla.com
push dateFri, 28 Sep 2018 08:54:16 +0000
treeherdermozilla-central@20d42e205b19 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1494518
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1494518 - Do not pass non-PromiseObject to JSRuntime::enqueuePromiseJob. r=till
js/src/builtin/Promise.cpp
js/src/vm/Runtime.cpp
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -1013,19 +1013,33 @@ EnqueuePromiseReactionJob(JSContext* cx,
     // instance with a non-default @@species value on the constructor) with a
     // function that returns objects that're not Promise (subclass) instances.
     // In that case, we just pretend we didn't have an object in the first
     // place.
     // If after all this we do have an object, wrap it in case we entered the
     // handler's compartment above, because we should pass objects from a
     // single compartment to the enqueuePromiseJob callback.
     RootedObject promise(cx, reaction->promise());
-    if (promise && promise->is<PromiseObject>()) {
-        if (!cx->compartment()->wrap(cx, &promise)) {
-            return false;
+    if (promise) {
+        if (promise->is<PromiseObject>()) {
+            if (!cx->compartment()->wrap(cx, &promise)) {
+                return false;
+            }
+        } else if (IsWrapper(promise)) {
+            // `promise` can be already-wrapped promise object at this point.
+            JSObject* unwrappedPromise = UncheckedUnwrap(promise);
+            if (unwrappedPromise->is<PromiseObject>()) {
+                if (!cx->compartment()->wrap(cx, &promise)) {
+                    return false;
+                }
+            } else {
+                promise = nullptr;
+            }
+        } else {
+            promise = nullptr;
         }
     }
 
     // Using objectFromIncumbentGlobal, we can derive the incumbent global by
     // unwrapping and then getting the global. This is very convoluted, but
     // much better than having to store the original global as a private value
     // because we couldn't wrap it to store it as a normal JS value.
     Rooted<GlobalObject*> global(cx);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -643,16 +643,20 @@ JSRuntime::enqueuePromiseJob(JSContext* 
                              Handle<GlobalObject*> incumbentGlobal)
 {
     MOZ_ASSERT(cx->enqueuePromiseJobCallback,
                "Must set a callback using JS::SetEnqueuePromiseJobCallback before using Promises");
 
     void* data = cx->enqueuePromiseJobCallbackData;
     RootedObject allocationSite(cx);
     if (promise) {
+#ifdef DEBUG
+        AssertSameCompartment(job, promise);
+#endif
+
         RootedObject unwrappedPromise(cx, promise);
         // While the job object is guaranteed to be unwrapped, the promise
         // might be wrapped. See the comments in EnqueuePromiseReactionJob in
         // builtin/Promise.cpp for details.
         if (IsWrapper(promise)) {
             unwrappedPromise = UncheckedUnwrap(promise);
         }
         if (unwrappedPromise->is<PromiseObject>()) {