contextify: tie lifetimes of context & sandbox

When the previous set of changes (bfff07b4) it was possible to have the
context get garbage collected while sandbox was still live. We need to
tie the lifetime of the context to the lifetime of the sandbox.

Fixes: https://github.com/nodejs/node/issues/5768
PR-URL: https://github.com/nodejs/node/pull/5786
Reviewed-By: jasnell - James M Snell <jasnell@gmail.com>
Reviewed-By: cjihrig - Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: trevnorris - Trevor Norris <trev.norris@gmail.com>
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Ali Ijaz Sheikh 2016-03-18 08:32:33 -07:00
Родитель be97db92af
Коммит a53b2ac4b1
3 изменённых файлов: 27 добавлений и 5 удалений

Просмотреть файл

@ -50,7 +50,8 @@ namespace node {
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \ #define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
V(alpn_buffer_private_symbol, "node:alpnBuffer") \ V(alpn_buffer_private_symbol, "node:alpnBuffer") \
V(arrow_message_private_symbol, "node:arrowMessage") \ V(arrow_message_private_symbol, "node:arrowMessage") \
V(contextify_private_symbol, "node:contextify") \ V(contextify_context_private_symbol, "node:contextify:context") \
V(contextify_global_private_symbol, "node:contextify:global") \
V(decorated_private_symbol, "node:decorated") \ V(decorated_private_symbol, "node:decorated") \
V(npn_buffer_private_symbol, "node:npnBuffer") \ V(npn_buffer_private_symbol, "node:npnBuffer") \
V(processed_private_symbol, "node:processed") \ V(processed_private_symbol, "node:processed") \

Просмотреть файл

@ -209,7 +209,17 @@ class ContextifyContext {
CHECK(!ctx.IsEmpty()); CHECK(!ctx.IsEmpty());
ctx->SetSecurityToken(env->context()->GetSecurityToken()); ctx->SetSecurityToken(env->context()->GetSecurityToken());
// We need to tie the lifetime of the sandbox object with the lifetime of
// newly created context. We do this by making them hold references to each
// other. The context can directly hold a reference to the sandbox as an
// embedder data field. However, we cannot hold a reference to a v8::Context
// directly in an Object, we instead hold onto the new context's global
// object instead (which then has a reference to the context).
ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj); ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj);
sandbox_obj->SetPrivate(env->context(),
env->contextify_global_private_symbol(),
ctx->Global());
env->AssignToContext(ctx); env->AssignToContext(ctx);
@ -270,7 +280,7 @@ class ContextifyContext {
CHECK( CHECK(
!sandbox->HasPrivate( !sandbox->HasPrivate(
env->context(), env->context(),
env->contextify_private_symbol()).FromJust()); env->contextify_context_private_symbol()).FromJust());
TryCatch try_catch(env->isolate()); TryCatch try_catch(env->isolate());
ContextifyContext* context = new ContextifyContext(env, sandbox); ContextifyContext* context = new ContextifyContext(env, sandbox);
@ -285,7 +295,7 @@ class ContextifyContext {
sandbox->SetPrivate( sandbox->SetPrivate(
env->context(), env->context(),
env->contextify_private_symbol(), env->contextify_context_private_symbol(),
External::New(env->isolate(), context)); External::New(env->isolate(), context));
} }
@ -300,7 +310,8 @@ class ContextifyContext {
Local<Object> sandbox = args[0].As<Object>(); Local<Object> sandbox = args[0].As<Object>();
auto result = auto result =
sandbox->HasPrivate(env->context(), env->contextify_private_symbol()); sandbox->HasPrivate(env->context(),
env->contextify_context_private_symbol());
args.GetReturnValue().Set(result.FromJust()); args.GetReturnValue().Set(result.FromJust());
} }
@ -315,7 +326,8 @@ class ContextifyContext {
Environment* env, Environment* env,
const Local<Object>& sandbox) { const Local<Object>& sandbox) {
auto maybe_value = auto maybe_value =
sandbox->GetPrivate(env->context(), env->contextify_private_symbol()); sandbox->GetPrivate(env->context(),
env->contextify_context_private_symbol());
Local<Value> context_external_v; Local<Value> context_external_v;
if (maybe_value.ToLocal(&context_external_v) && if (maybe_value.ToLocal(&context_external_v) &&
context_external_v->IsExternal()) { context_external_v->IsExternal()) {

Просмотреть файл

@ -1,4 +1,5 @@
'use strict'; 'use strict';
// Flags: --expose-gc
require('../common'); require('../common');
var assert = require('assert'); var assert = require('assert');
@ -18,3 +19,11 @@ console.error('test updating context');
result = vm.runInContext('var foo = 3;', context); result = vm.runInContext('var foo = 3;', context);
assert.equal(3, context.foo); assert.equal(3, context.foo);
assert.equal('lala', context.thing); assert.equal('lala', context.thing);
// https://github.com/nodejs/node/issues/5768
console.error('run in contextified sandbox without referencing the context');
var sandbox = {x: 1};
vm.createContext(sandbox);
gc();
vm.runInContext('x = 2', sandbox);
// Should not crash.