Bug 1298597 - Properly handle the target Promise having been nuked in resolve/reject functions for xray'd Promises. r?jandem
MozReview-Commit-ID: EBAwzff9vOM
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -164,19 +164,23 @@ ResolvePromise(JSContext* cx, Handle<Pro
// ES2016, 25.4.1.4.
static MOZ_MUST_USE bool
FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue value_) {
Rooted<PromiseObject*> promise(cx);
RootedValue value(cx, value_);
mozilla::Maybe<AutoCompartment> ac;
- if (!IsWrapper(promiseObj)) {
+ if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
+ if (JS_IsDeadWrapper(promiseObj)) {
+ JS_ReportErrorNumber(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;
}
MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
@@ -185,19 +189,23 @@ FulfillMaybeWrappedPromise(JSContext *cx
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool
RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue reason_) {
Rooted<PromiseObject*> promise(cx);
RootedValue reason(cx, reason_);
mozilla::Maybe<AutoCompartment> ac;
- if (!IsWrapper(promiseObj)) {
+ if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
+ if (JS_IsDeadWrapper(promiseObj)) {
+ JS_ReportErrorNumber(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
// values might be wrapped into a wrapper that throws whenever the
// Promise's reaction handler wants to do anything useful with it. To
// avoid that situation, we synthesize a generic error that doesn't
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_resolve_dead_promise.js
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* See https://bugzilla.mozilla.org/show_bug.cgi?id=1298597 */
+
+function run_test()
+{
+ var sb = Components.utils.Sandbox("http://www.blah.com");
+ var resolveFun;
+ var p1 = new sb.Promise((res, rej) => {resolveFun = res});
+ var rejectFun;
+ var p2 = new sb.Promise((res, rej) => {rejectFun = rej});
+ Components.utils.nukeSandbox(sb);
+ do_check_true(Components.utils.isDeadWrapper(sb), "sb should be dead");
+ do_check_true(Components.utils.isDeadWrapper(p1), "p1 should be dead");
+ do_check_true(Components.utils.isDeadWrapper(p2), "p2 should be dead");
+
+ var exception;
+
+ try{
+ resolveFun(1);
+ do_check_true(false);
+ } catch (e) {
+ exception = e;
+ }
+ do_check_true(exception.toString().includes("can't access dead object"),
+ "Resolving dead wrapped promise should throw");
+
+ exception = undefined;
+ try{
+ rejectFun(1);
+ do_check_true(false);
+ } catch (e) {
+ exception = e;
+ }
+ do_check_true(exception.toString().includes("can't access dead object"),
+ "Rejecting dead wrapped promise should throw");
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -128,8 +128,9 @@ head = head_watchdog.js
[test_watchdog_hibernate.js]
head = head_watchdog.js
[test_weak_keys.js]
[test_writeToGlobalPrototype.js]
[test_xpcwn_tamperproof.js]
[test_xrayed_iterator.js]
[test_xray_SavedFrame.js]
[test_xray_SavedFrame-02.js]
+[test_resolve_dead_promise.js]