Skip to content

Commit

Permalink
contextify: tie lifetimes of context & sandbox
Browse files Browse the repository at this point in the history
When the previous set of changes (bfff07b) 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: nodejs#5768
PR-URL: nodejs#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>
  • Loading branch information
ofrobots committed Mar 19, 2016
1 parent be97db9 commit a53b2ac
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ namespace node {
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
V(alpn_buffer_private_symbol, "node:alpnBuffer") \
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(npn_buffer_private_symbol, "node:npnBuffer") \
V(processed_private_symbol, "node:processed") \
Expand Down
20 changes: 16 additions & 4 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,17 @@ class ContextifyContext {

CHECK(!ctx.IsEmpty());
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);
sandbox_obj->SetPrivate(env->context(),
env->contextify_global_private_symbol(),
ctx->Global());

env->AssignToContext(ctx);

Expand Down Expand Up @@ -270,7 +280,7 @@ class ContextifyContext {
CHECK(
!sandbox->HasPrivate(
env->context(),
env->contextify_private_symbol()).FromJust());
env->contextify_context_private_symbol()).FromJust());

TryCatch try_catch(env->isolate());
ContextifyContext* context = new ContextifyContext(env, sandbox);
Expand All @@ -285,7 +295,7 @@ class ContextifyContext {

sandbox->SetPrivate(
env->context(),
env->contextify_private_symbol(),
env->contextify_context_private_symbol(),
External::New(env->isolate(), context));
}

Expand All @@ -300,7 +310,8 @@ class ContextifyContext {
Local<Object> sandbox = args[0].As<Object>();

auto result =
sandbox->HasPrivate(env->context(), env->contextify_private_symbol());
sandbox->HasPrivate(env->context(),
env->contextify_context_private_symbol());
args.GetReturnValue().Set(result.FromJust());
}

Expand All @@ -315,7 +326,8 @@ class ContextifyContext {
Environment* env,
const Local<Object>& sandbox) {
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;
if (maybe_value.ToLocal(&context_external_v) &&
context_external_v->IsExternal()) {
Expand Down
9 changes: 9 additions & 0 deletions test/parallel/test-vm-create-and-run-in-context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
// Flags: --expose-gc
require('../common');
var assert = require('assert');

Expand All @@ -18,3 +19,11 @@ console.error('test updating context');
result = vm.runInContext('var foo = 3;', context);
assert.equal(3, context.foo);
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.

0 comments on commit a53b2ac

Please sign in to comment.