зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1515754 - Enter the reaction's realm in EnqueuePromiseReactionJob before creating the job. r=arai
This is consistent with what we do for cross-compartment wrappers and avoids problems with running jobs against a dying global (Gecko drops such jobs). I added a globalOfFirstJobInQueue() shell function so I could write a test that checks both the compartment-per-global and single-compartment cases. Differential Revision: https://phabricator.services.mozilla.com/D15176 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
ecaf5bdea0
Коммит
1d8954ace9
|
@ -959,6 +959,13 @@ MOZ_MUST_USE static bool EnqueuePromiseReactionJob(
|
|||
if (!IsProxy(reactionObj)) {
|
||||
MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
|
||||
reaction = &reactionObj->as<PromiseReactionRecord>();
|
||||
if (cx->realm() != reaction->realm()) {
|
||||
// If the compartment has multiple realms, create the job in the
|
||||
// reaction's realm. This is consistent with the code in the else-branch
|
||||
// and avoids problems with running jobs against a dying global (Gecko
|
||||
// drops such jobs).
|
||||
ar.emplace(cx, reaction);
|
||||
}
|
||||
} else {
|
||||
JSObject* unwrappedReactionObj = UncheckedUnwrap(reactionObj);
|
||||
if (JS_IsDeadWrapper(unwrappedReactionObj)) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Test that jobs added to the promise job queue have a global that's consistent
|
||||
// with and without same-compartment realms.
|
||||
|
||||
var g1 = newGlobal();
|
||||
var g2 = newGlobal({sameCompartmentAs: this});
|
||||
|
||||
// EnqueuePromiseReactionJob, handler is a primitive.
|
||||
// Job's global is the reaction's global.
|
||||
function test1(g) {
|
||||
var resolve;
|
||||
var p = new Promise(res => { resolve = res; });
|
||||
g.Promise.prototype.then.call(p, 1);
|
||||
resolve();
|
||||
assertEq(globalOfFirstJobInQueue(), g);
|
||||
drainJobQueue();
|
||||
}
|
||||
test1(g1);
|
||||
test1(g2);
|
||||
|
||||
// EnqueuePromiseReactionJob, handler is an object.
|
||||
// Job's global is the handler's global.
|
||||
function test2(g) {
|
||||
var resolve;
|
||||
var p = new Promise(res => { resolve = res; });
|
||||
p.then(new g.Function());
|
||||
resolve();
|
||||
assertEq(globalOfFirstJobInQueue(), g);
|
||||
drainJobQueue();
|
||||
}
|
||||
test2(g1);
|
||||
test2(g2);
|
|
@ -1036,6 +1036,24 @@ static bool DrainJobQueue(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool GlobalOfFirstJobInQueue(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (cx->jobQueue->empty()) {
|
||||
JS_ReportErrorASCII(cx, "Job queue is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject job(cx, cx->jobQueue->front());
|
||||
RootedObject global(cx, &job->nonCCWGlobal());
|
||||
if (!cx->compartment()->wrap(cx, &global)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*global);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ForwardingPromiseRejectionTrackerCallback(
|
||||
JSContext* cx, JS::HandleObject promise,
|
||||
JS::PromiseRejectionHandlingState state, void* data) {
|
||||
|
@ -8617,6 +8635,11 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
|
|||
"enqueueJob(fn)",
|
||||
" Enqueue 'fn' on the shell's job queue."),
|
||||
|
||||
JS_FN_HELP("globalOfFirstJobInQueue", GlobalOfFirstJobInQueue, 0, 0,
|
||||
"globalOfFirstJobInQueue()",
|
||||
" Returns the global of the first item in the job queue. Throws an exception\n"
|
||||
" if the queue is empty.\n"),
|
||||
|
||||
JS_FN_HELP("drainJobQueue", DrainJobQueue, 0, 0,
|
||||
"drainJobQueue()",
|
||||
"Take jobs from the shell's job queue in FIFO order and run them until the\n"
|
||||
|
|
Загрузка…
Ссылка в новой задаче