src: do not add .domain to promises in VM contexts

The promises are still tracked, and their handlers will still execute in
the correct domain. The creation domain is simply hidden.

PR-URL: https://github.com/nodejs/node/pull/15695
Fixes: https://github.com/nodejs/node/issues/15673
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Timothy Gu 2017-09-29 22:15:24 -07:00
parent a3cd8ed168
commit 806857712f
No known key found for this signature in database
GPG Key ID: 7FE6B095B582B0D4
4 changed files with 37 additions and 9 deletions

View File

@ -1,6 +1,12 @@
# Domain
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/REPLACEME
description: Any `Promise`s created in VM contexts no longer have a
`.domain` property. Their handlers are still executed in the
proper domain, however, and `Promise`s created in the main
context still possess a `.domain` property.
- version: v8.0.0
pr-url: https://github.com/nodejs/node/pull/12489
description: Handlers for `Promise`s are now invoked in the domain in which

View File

@ -93,6 +93,7 @@ class ModuleWrap;
V(npn_buffer_private_symbol, "node:npnBuffer") \
V(processed_private_symbol, "node:processed") \
V(selected_npn_buffer_private_symbol, "node:selectedNpnBuffer") \
V(domain_private_symbol, "node:domain") \
// Strings are per-isolate primitives but Environment proxies them
// for the sake of convenience. Strings should be ASCII-only.

View File

@ -1156,8 +1156,19 @@ bool ShouldAbortOnUncaughtException(Isolate* isolate) {
}
Local<Value> GetDomainProperty(Environment* env, Local<Object> object) {
Local<Value> domain_v =
object->GetPrivate(env->context(), env->domain_private_symbol())
.ToLocalChecked();
if (domain_v->IsObject()) {
return domain_v;
}
return object->Get(env->context(), env->domain_string()).ToLocalChecked();
}
void DomainEnter(Environment* env, Local<Object> object) {
Local<Value> domain_v = object->Get(env->domain_string());
Local<Value> domain_v = GetDomainProperty(env, object);
if (domain_v->IsObject()) {
Local<Object> domain = domain_v.As<Object>();
Local<Value> enter_v = domain->Get(env->enter_string());
@ -1172,7 +1183,7 @@ void DomainEnter(Environment* env, Local<Object> object) {
void DomainExit(Environment* env, v8::Local<v8::Object> object) {
Local<Value> domain_v = object->Get(env->domain_string());
Local<Value> domain_v = GetDomainProperty(env, object);
if (domain_v->IsObject()) {
Local<Object> domain = domain_v.As<Object>();
Local<Value> exit_v = domain->Get(env->exit_string());
@ -1194,10 +1205,16 @@ void DomainPromiseHook(PromiseHookType type,
Local<Context> context = env->context();
if (type == PromiseHookType::kInit && env->in_domain()) {
promise->Set(context,
env->domain_string(),
env->domain_array()->Get(context,
0).ToLocalChecked()).FromJust();
Local<Value> domain_obj =
env->domain_array()->Get(context, 0).ToLocalChecked();
if (promise->CreationContext() == context) {
promise->Set(context, env->domain_string(), domain_obj).FromJust();
} else {
// Do not expose object from another context publicly in promises created
// in non-main contexts.
promise->SetPrivate(context, env->domain_private_symbol(), domain_obj)
.FromJust();
}
return;
}

View File

@ -31,9 +31,13 @@ common.crashOnUnhandledRejection();
const d = domain.create();
d.run(common.mustCall(() => {
vm.runInNewContext(`Promise.resolve().then(common.mustCall(() => {
assert.strictEqual(process.domain, d);
}));`, { common, assert, process, d });
vm.runInNewContext(`
const promise = Promise.resolve();
assert.strictEqual(promise.domain, undefined);
promise.then(common.mustCall(() => {
assert.strictEqual(process.domain, d);
}));
`, { common, assert, process, d });
}));
}