Skip to content

Commit 4ad54dc

Browse files
committed
vm: fix symbol access
By using the new SetHandler API instead of SetNamedPropertyHandler, we can intercept symbols now. Fixes #884.
1 parent ec3905b commit 4ad54dc

File tree

2 files changed

+65
-20
lines changed

2 files changed

+65
-20
lines changed

src/node_contextify.cc

+42-20
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ using v8::HandleScope;
2626
using v8::Integer;
2727
using v8::Isolate;
2828
using v8::Local;
29+
using v8::MaybeLocal;
30+
using v8::Name;
31+
using v8::NamedPropertyHandlerConfiguration;
2932
using v8::None;
3033
using v8::Object;
3134
using v8::ObjectTemplate;
@@ -202,12 +205,14 @@ class ContextifyContext {
202205

203206
Local<ObjectTemplate> object_template =
204207
function_template->InstanceTemplate();
205-
object_template->SetNamedPropertyHandler(GlobalPropertyGetterCallback,
208+
209+
NamedPropertyHandlerConfiguration config(GlobalPropertyGetterCallback,
206210
GlobalPropertySetterCallback,
207211
GlobalPropertyQueryCallback,
208212
GlobalPropertyDeleterCallback,
209213
GlobalPropertyEnumeratorCallback,
210214
CreateDataWrapper(env));
215+
object_template->SetHandler(config);
211216

212217
Local<Context> ctx = Context::New(env->isolate(), nullptr, object_template);
213218
if (!ctx.IsEmpty())
@@ -342,7 +347,7 @@ class ContextifyContext {
342347

343348

344349
static void GlobalPropertyGetterCallback(
345-
Local<String> property,
350+
Local<Name> property,
346351
const PropertyCallbackInfo<Value>& args) {
347352
Isolate* isolate = args.GetIsolate();
348353
HandleScope scope(isolate);
@@ -351,22 +356,27 @@ class ContextifyContext {
351356
Unwrap<ContextifyContext>(args.Data().As<Object>());
352357

353358
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
354-
Local<Value> rv = sandbox->GetRealNamedProperty(property);
359+
MaybeLocal<Value> rv =
360+
sandbox->GetRealNamedProperty(ctx->context(), property);
355361
if (rv.IsEmpty()) {
356362
Local<Object> proxy_global = PersistentToLocal(isolate,
357363
ctx->proxy_global_);
358-
rv = proxy_global->GetRealNamedProperty(property);
359-
}
360-
if (!rv.IsEmpty() && rv == ctx->sandbox_) {
361-
rv = PersistentToLocal(isolate, ctx->proxy_global_);
364+
rv = proxy_global->GetRealNamedProperty(ctx->context(), property);
362365
}
363366

364-
args.GetReturnValue().Set(rv);
367+
Local<Value> localRV;
368+
if (rv.ToLocal(&localRV)) {
369+
if (localRV == ctx->sandbox_) {
370+
localRV = PersistentToLocal(isolate, ctx->proxy_global_);
371+
}
372+
373+
args.GetReturnValue().Set(localRV);
374+
}
365375
}
366376

367377

368378
static void GlobalPropertySetterCallback(
369-
Local<String> property,
379+
Local<Name> property,
370380
Local<Value> value,
371381
const PropertyCallbackInfo<Value>& args) {
372382
Isolate* isolate = args.GetIsolate();
@@ -380,7 +390,7 @@ class ContextifyContext {
380390

381391

382392
static void GlobalPropertyQueryCallback(
383-
Local<String> property,
393+
Local<Name> property,
384394
const PropertyCallbackInfo<Integer>& args) {
385395
Isolate* isolate = args.GetIsolate();
386396
HandleScope scope(isolate);
@@ -392,31 +402,43 @@ class ContextifyContext {
392402
Local<Object> proxy_global = PersistentToLocal(isolate,
393403
ctx->proxy_global_);
394404

395-
if (sandbox->HasRealNamedProperty(property)) {
396-
PropertyAttribute propAttr =
397-
sandbox->GetRealNamedPropertyAttributes(property).FromJust();
398-
args.GetReturnValue().Set(propAttr);
399-
} else if (proxy_global->HasRealNamedProperty(property)) {
405+
bool in_sandbox =
406+
sandbox->HasRealNamedProperty(ctx->context(), property).FromMaybe(false);
407+
408+
if (in_sandbox) {
400409
PropertyAttribute propAttr =
401-
proxy_global->GetRealNamedPropertyAttributes(property).FromJust();
410+
sandbox->
411+
GetRealNamedPropertyAttributes(ctx->context(), property).FromJust();
402412
args.GetReturnValue().Set(propAttr);
403413
} else {
404-
args.GetReturnValue().Set(None);
414+
bool in_proxy_global =
415+
proxy_global->HasRealNamedProperty(ctx->context(), property)
416+
.FromMaybe(false);
417+
if (in_proxy_global) {
418+
PropertyAttribute propAttr =
419+
proxy_global->
420+
GetRealNamedPropertyAttributes(ctx->context(), property)
421+
.FromJust();
422+
args.GetReturnValue().Set(propAttr);
423+
}
424+
else {
425+
args.GetReturnValue().Set(None);
426+
}
405427
}
406428
}
407429

408430

409431
static void GlobalPropertyDeleterCallback(
410-
Local<String> property,
432+
Local<Name> property,
411433
const PropertyCallbackInfo<Boolean>& args) {
412434
Isolate* isolate = args.GetIsolate();
413435
HandleScope scope(isolate);
414436

415437
ContextifyContext* ctx =
416438
Unwrap<ContextifyContext>(args.Data().As<Object>());
439+
Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
417440

418-
bool success = PersistentToLocal(isolate,
419-
ctx->sandbox_)->Delete(property);
441+
bool success = sandbox->Delete(ctx->context(), property).FromMaybe(false);
420442
args.GetReturnValue().Set(success);
421443
}
422444

test/parallel/test-vm-symbols.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var common = require('../common');
2+
var assert = require('assert');
3+
4+
var vm = require('vm');
5+
6+
var symbol = Symbol();
7+
8+
function Document() {
9+
this[symbol] = 'foo';
10+
}
11+
12+
Document.prototype.getSymbolValue = function () {
13+
return this[symbol];
14+
};
15+
16+
var context = new Document();
17+
vm.createContext(context);
18+
19+
assert.equal(context.getSymbolValue(), 'foo',
20+
'should return symbol-keyed value from the outside');
21+
22+
assert.equal(vm.runInContext('this.getSymbolValue()', context), 'foo',
23+
'should return symbol-keyed value from the inside');

0 commit comments

Comments
 (0)