Skip to content

Commit a53b2ac

Browse files
committed
contextify: tie lifetimes of context & sandbox
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: #5768 PR-URL: #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>
1 parent be97db9 commit a53b2ac

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

src/env.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ namespace node {
5050
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
5151
V(alpn_buffer_private_symbol, "node:alpnBuffer") \
5252
V(arrow_message_private_symbol, "node:arrowMessage") \
53-
V(contextify_private_symbol, "node:contextify") \
53+
V(contextify_context_private_symbol, "node:contextify:context") \
54+
V(contextify_global_private_symbol, "node:contextify:global") \
5455
V(decorated_private_symbol, "node:decorated") \
5556
V(npn_buffer_private_symbol, "node:npnBuffer") \
5657
V(processed_private_symbol, "node:processed") \

src/node_contextify.cc

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,17 @@ class ContextifyContext {
209209

210210
CHECK(!ctx.IsEmpty());
211211
ctx->SetSecurityToken(env->context()->GetSecurityToken());
212+
213+
// We need to tie the lifetime of the sandbox object with the lifetime of
214+
// newly created context. We do this by making them hold references to each
215+
// other. The context can directly hold a reference to the sandbox as an
216+
// embedder data field. However, we cannot hold a reference to a v8::Context
217+
// directly in an Object, we instead hold onto the new context's global
218+
// object instead (which then has a reference to the context).
212219
ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj);
220+
sandbox_obj->SetPrivate(env->context(),
221+
env->contextify_global_private_symbol(),
222+
ctx->Global());
213223

214224
env->AssignToContext(ctx);
215225

@@ -270,7 +280,7 @@ class ContextifyContext {
270280
CHECK(
271281
!sandbox->HasPrivate(
272282
env->context(),
273-
env->contextify_private_symbol()).FromJust());
283+
env->contextify_context_private_symbol()).FromJust());
274284

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

286296
sandbox->SetPrivate(
287297
env->context(),
288-
env->contextify_private_symbol(),
298+
env->contextify_context_private_symbol(),
289299
External::New(env->isolate(), context));
290300
}
291301

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

302312
auto result =
303-
sandbox->HasPrivate(env->context(), env->contextify_private_symbol());
313+
sandbox->HasPrivate(env->context(),
314+
env->contextify_context_private_symbol());
304315
args.GetReturnValue().Set(result.FromJust());
305316
}
306317

@@ -315,7 +326,8 @@ class ContextifyContext {
315326
Environment* env,
316327
const Local<Object>& sandbox) {
317328
auto maybe_value =
318-
sandbox->GetPrivate(env->context(), env->contextify_private_symbol());
329+
sandbox->GetPrivate(env->context(),
330+
env->contextify_context_private_symbol());
319331
Local<Value> context_external_v;
320332
if (maybe_value.ToLocal(&context_external_v) &&
321333
context_external_v->IsExternal()) {

test/parallel/test-vm-create-and-run-in-context.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
// Flags: --expose-gc
23
require('../common');
34
var assert = require('assert');
45

@@ -18,3 +19,11 @@ console.error('test updating context');
1819
result = vm.runInContext('var foo = 3;', context);
1920
assert.equal(3, context.foo);
2021
assert.equal('lala', context.thing);
22+
23+
// https://github.com/nodejs/node/issues/5768
24+
console.error('run in contextified sandbox without referencing the context');
25+
var sandbox = {x: 1};
26+
vm.createContext(sandbox);
27+
gc();
28+
vm.runInContext('x = 2', sandbox);
29+
// Should not crash.

0 commit comments

Comments
 (0)