Bug 1346012 - Handle dead object wrappers in more places in Promise code. r=shu
☠☠ backed out by e0bd14f23ac9 ☠ ☠
authorTill Schneidereit <till@tillschneidereit.net>
Fri, 24 Mar 2017 22:49:38 -0700
changeset 351996 35e0a23e1c89bc55aa667915d5af41e006c9ed3f
parent 351995 415cd9f874580ba859372b48bfc690bc13bf3b24
child 351997 bb79e576b61769175c0a9d82441d5f73e1c94909
push id31624
push userarchaeopteryx@coole-files.de
push dateSat, 08 Apr 2017 20:49:20 +0000
treeherdermozilla-central@2a3ecdb7d1ea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1346012
milestone55.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 1346012 - Handle dead object wrappers in more places in Promise code. r=shu MozReview-Commit-ID: HlmKwoMub9D
js/src/builtin/Promise.cpp
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -485,26 +485,29 @@ EnqueuePromiseReactionJob(JSContext* cx,
 {
     // The reaction might have been stored on a Promise from another
     // compartment, which means it would've been wrapped in a CCW.
     // To properly handle that case here, unwrap it and enter its
     // compartment, where the job creation should take place anyway.
     Rooted<PromiseReactionRecord*> reaction(cx);
     RootedValue handlerArg(cx, handlerArg_);
     mozilla::Maybe<AutoCompartment> ac;
-    if (IsWrapper(reactionObj)) {
-        RootedObject unwrappedReactionObj(cx, UncheckedUnwrap(reactionObj));
-        if (!unwrappedReactionObj)
+    if (!IsProxy(reactionObj)) {
+        MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
+        reaction = &reactionObj->as<PromiseReactionRecord>();
+    } else {
+        if (JS_IsDeadWrapper(CheckedUnwrap(reactionObj))) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
-        ac.emplace(cx, unwrappedReactionObj);
-        reaction = &unwrappedReactionObj->as<PromiseReactionRecord>();
-        if (!cx->compartment()->wrap(cx, &handlerArg))
+        }
+        reaction = &UncheckedUnwrap(reactionObj)->as<PromiseReactionRecord>();
+        MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
+        ac.emplace(cx, reaction);
+        if (!reaction->compartment()->wrap(cx, &handlerArg))
             return false;
-    } else {
-        reaction = &reactionObj->as<PromiseReactionRecord>();
     }
 
     // Must not enqueue a reaction job more than once.
     MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
 
     assertSameCompartment(cx, handlerArg);
     reaction->setHandlerArg(handlerArg.get());
 
@@ -635,17 +638,17 @@ FulfillMaybeWrappedPromise(JSContext *cx
 {
     Rooted<PromiseObject*> promise(cx);
     RootedValue value(cx, value_);
 
     mozilla::Maybe<AutoCompartment> ac;
     if (!IsProxy(promiseObj)) {
         promise = &promiseObj->as<PromiseObject>();
     } else {
-        if (JS_IsDeadWrapper(promiseObj)) {
+        if (JS_IsDeadWrapper(CheckedUnwrap(promiseObj))) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
         promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
         ac.emplace(cx, promise);
         if (!promise->compartment()->wrap(cx, &value))
             return false;
     }
@@ -785,17 +788,17 @@ RejectMaybeWrappedPromise(JSContext *cx,
 {
     Rooted<PromiseObject*> promise(cx);
     RootedValue reason(cx, reason_);
 
     mozilla::Maybe<AutoCompartment> ac;
     if (!IsProxy(promiseObj)) {
         promise = &promiseObj->as<PromiseObject>();
     } else {
-        if (JS_IsDeadWrapper(promiseObj)) {
+        if (JS_IsDeadWrapper(CheckedUnwrap(promiseObj))) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
             return false;
         }
         promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
         ac.emplace(cx, promise);
 
         // The rejection reason might've been created in a compartment with higher
         // privileges than the Promise's. In that case, object-type rejection
@@ -926,18 +929,25 @@ PromiseReactionJob(JSContext* cx, unsign
     // To ensure that the embedding ends up with the right entry global, we're
     // guaranteeing that the reaction job function gets created in the same
     // compartment as the handler function. That's not necessarily the global
     // that the job was triggered from, though.
     // We can find the triggering global via the job's reaction record. To go
     // back, we check if the reaction is a wrapper and if so, unwrap it and
     // enter its compartment.
     mozilla::Maybe<AutoCompartment> ac;
-    if (IsWrapper(reactionObj)) {
+    if (!IsProxy(reactionObj)) {
+        MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
+    } else {
+        if (JS_IsDeadWrapper(CheckedUnwrap(reactionObj))) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+            return false;
+        }
         reactionObj = UncheckedUnwrap(reactionObj);
+        MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
         ac.emplace(cx, reactionObj);
     }
 
     // Steps 1-2.
     Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
     if (reaction->isAsyncFunctionAwait())
         return AsyncFunctionAwaitPromiseReactionJob(cx, reaction, args.rval());
     if (reaction->isAsyncGeneratorAwait())
@@ -2805,17 +2815,21 @@ BlockOnPromise(JSContext* cx, HandleValu
     // other than the original value of |Promise| was used to create it).
     // To have both that object and |blockedPromise| show up as dependent
     // promises in the debugger, add a dummy reaction to the list of reject
     // reactions that contains |blockedPromise|, but otherwise does nothing.
     RootedObject unwrappedPromiseObj(cx, promiseObj);
     RootedObject blockedPromise(cx, blockedPromise_);
 
     mozilla::Maybe<AutoCompartment> ac;
-    if (IsWrapper(promiseObj)) {
+    if (IsProxy(promiseObj)) {
+        if (JS_IsDeadWrapper(CheckedUnwrap(promiseObj))) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+            return false;
+        }
         unwrappedPromiseObj = CheckedUnwrap(promiseObj);
         if (!unwrappedPromiseObj)
             return false;
         ac.emplace(cx, unwrappedPromiseObj);
         if (!cx->compartment()->wrap(cx, &blockedPromise))
             return false;
     }
 
@@ -2859,17 +2873,21 @@ AddPromiseReaction(JSContext* cx, Handle
         return true;
     }
 
     RootedObject reactionsObj(cx, &reactionsVal.toObject());
 
     // If only a single reaction exists, it's stored directly instead of in a
     // list. In that case, `reactionsObj` might be a wrapper, which we can
     // always safely unwrap.
-    if (IsWrapper(reactionsObj)) {
+    if (IsProxy(reactionsObj)) {
+        if (JS_IsDeadWrapper(CheckedUnwrap(reactionsObj))) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+            return false;
+        }
         reactionsObj = UncheckedUnwrap(reactionsObj);
         MOZ_ASSERT(reactionsObj->is<PromiseReactionRecord>());
     }
 
     if (reactionsObj->is<PromiseReactionRecord>()) {
         // If a single reaction existed so far, create a list and store the
         // old and the new reaction in it.
         reactions = NewDenseFullyAllocatedArray(cx, 2);