mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
vm,src: add property query interceptors
Fixes: https://github.com/nodejs/node/issues/52720 PR-URL: https://github.com/nodejs/node/pull/53172 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
@@ -51,6 +51,7 @@ using v8::FunctionTemplate;
|
||||
using v8::HandleScope;
|
||||
using v8::IndexedPropertyHandlerConfiguration;
|
||||
using v8::Int32;
|
||||
using v8::Integer;
|
||||
using v8::Intercepted;
|
||||
using v8::Isolate;
|
||||
using v8::Just;
|
||||
@@ -176,20 +177,22 @@ void ContextifyContext::InitializeGlobalTemplates(IsolateData* isolate_data) {
|
||||
NamedPropertyHandlerConfiguration config(
|
||||
PropertyGetterCallback,
|
||||
PropertySetterCallback,
|
||||
PropertyDescriptorCallback,
|
||||
PropertyQueryCallback,
|
||||
PropertyDeleterCallback,
|
||||
PropertyEnumeratorCallback,
|
||||
PropertyDefinerCallback,
|
||||
PropertyDescriptorCallback,
|
||||
{},
|
||||
PropertyHandlerFlags::kHasNoSideEffect);
|
||||
|
||||
IndexedPropertyHandlerConfiguration indexed_config(
|
||||
IndexedPropertyGetterCallback,
|
||||
IndexedPropertySetterCallback,
|
||||
IndexedPropertyDescriptorCallback,
|
||||
IndexedPropertyQueryCallback,
|
||||
IndexedPropertyDeleterCallback,
|
||||
PropertyEnumeratorCallback,
|
||||
IndexedPropertyDefinerCallback,
|
||||
IndexedPropertyDescriptorCallback,
|
||||
{},
|
||||
PropertyHandlerFlags::kHasNoSideEffect);
|
||||
|
||||
@@ -354,12 +357,14 @@ void ContextifyContext::RegisterExternalReferences(
|
||||
ExternalReferenceRegistry* registry) {
|
||||
registry->Register(MakeContext);
|
||||
registry->Register(CompileFunction);
|
||||
registry->Register(PropertyQueryCallback);
|
||||
registry->Register(PropertyGetterCallback);
|
||||
registry->Register(PropertySetterCallback);
|
||||
registry->Register(PropertyDescriptorCallback);
|
||||
registry->Register(PropertyDeleterCallback);
|
||||
registry->Register(PropertyEnumeratorCallback);
|
||||
registry->Register(PropertyDefinerCallback);
|
||||
registry->Register(IndexedPropertyQueryCallback);
|
||||
registry->Register(IndexedPropertyGetterCallback);
|
||||
registry->Register(IndexedPropertySetterCallback);
|
||||
registry->Register(IndexedPropertyDescriptorCallback);
|
||||
@@ -458,6 +463,51 @@ bool ContextifyContext::IsStillInitializing(const ContextifyContext* ctx) {
|
||||
return ctx == nullptr || ctx->context_.IsEmpty();
|
||||
}
|
||||
|
||||
// static
|
||||
Intercepted ContextifyContext::PropertyQueryCallback(
|
||||
Local<Name> property, const PropertyCallbackInfo<Integer>& args) {
|
||||
ContextifyContext* ctx = ContextifyContext::Get(args);
|
||||
|
||||
// Still initializing
|
||||
if (IsStillInitializing(ctx)) {
|
||||
return Intercepted::kNo;
|
||||
}
|
||||
|
||||
Local<Context> context = ctx->context();
|
||||
Local<Object> sandbox = ctx->sandbox();
|
||||
|
||||
PropertyAttribute attr;
|
||||
|
||||
Maybe<bool> maybe_has = sandbox->HasRealNamedProperty(context, property);
|
||||
if (maybe_has.IsNothing()) {
|
||||
return Intercepted::kNo;
|
||||
} else if (maybe_has.FromJust()) {
|
||||
Maybe<PropertyAttribute> maybe_attr =
|
||||
sandbox->GetRealNamedPropertyAttributes(context, property);
|
||||
if (!maybe_attr.To(&attr)) {
|
||||
return Intercepted::kNo;
|
||||
}
|
||||
args.GetReturnValue().Set(attr);
|
||||
return Intercepted::kYes;
|
||||
} else {
|
||||
maybe_has = ctx->global_proxy()->HasRealNamedProperty(context, property);
|
||||
if (maybe_has.IsNothing()) {
|
||||
return Intercepted::kNo;
|
||||
} else if (maybe_has.FromJust()) {
|
||||
Maybe<PropertyAttribute> maybe_attr =
|
||||
ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
|
||||
property);
|
||||
if (!maybe_attr.To(&attr)) {
|
||||
return Intercepted::kNo;
|
||||
}
|
||||
args.GetReturnValue().Set(attr);
|
||||
return Intercepted::kYes;
|
||||
}
|
||||
}
|
||||
|
||||
return Intercepted::kNo;
|
||||
}
|
||||
|
||||
// static
|
||||
Intercepted ContextifyContext::PropertyGetterCallback(
|
||||
Local<Name> property, const PropertyCallbackInfo<Value>& args) {
|
||||
@@ -709,6 +759,20 @@ void ContextifyContext::PropertyEnumeratorCallback(
|
||||
args.GetReturnValue().Set(properties);
|
||||
}
|
||||
|
||||
// static
|
||||
Intercepted ContextifyContext::IndexedPropertyQueryCallback(
|
||||
uint32_t index, const PropertyCallbackInfo<Integer>& args) {
|
||||
ContextifyContext* ctx = ContextifyContext::Get(args);
|
||||
|
||||
// Still initializing
|
||||
if (IsStillInitializing(ctx)) {
|
||||
return Intercepted::kNo;
|
||||
}
|
||||
|
||||
return ContextifyContext::PropertyQueryCallback(
|
||||
Uint32ToName(ctx->context(), index), args);
|
||||
}
|
||||
|
||||
// static
|
||||
Intercepted ContextifyContext::IndexedPropertyGetterCallback(
|
||||
uint32_t index, const PropertyCallbackInfo<Value>& args) {
|
||||
|
||||
@@ -96,6 +96,9 @@ class ContextifyContext : public BaseObject {
|
||||
const errors::TryCatchScope& try_catch);
|
||||
static void WeakCallback(
|
||||
const v8::WeakCallbackInfo<ContextifyContext>& data);
|
||||
static v8::Intercepted PropertyQueryCallback(
|
||||
v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Integer>& args);
|
||||
static v8::Intercepted PropertyGetterCallback(
|
||||
v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
@@ -115,6 +118,8 @@ class ContextifyContext : public BaseObject {
|
||||
const v8::PropertyCallbackInfo<v8::Boolean>& args);
|
||||
static void PropertyEnumeratorCallback(
|
||||
const v8::PropertyCallbackInfo<v8::Array>& args);
|
||||
static v8::Intercepted IndexedPropertyQueryCallback(
|
||||
uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& args);
|
||||
static v8::Intercepted IndexedPropertyGetterCallback(
|
||||
uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
static v8::Intercepted IndexedPropertySetterCallback(
|
||||
|
||||
83
test/parallel/test-vm-global-property-prototype.js
Normal file
83
test/parallel/test-vm-global-property-prototype.js
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const vm = require('vm');
|
||||
|
||||
const sandbox = {
|
||||
onSelf: 'onSelf',
|
||||
};
|
||||
|
||||
function onSelfGetter() {
|
||||
return 'onSelfGetter';
|
||||
}
|
||||
|
||||
Object.defineProperty(sandbox, 'onSelfGetter', {
|
||||
get: onSelfGetter,
|
||||
});
|
||||
|
||||
Object.defineProperty(sandbox, 1, {
|
||||
value: 'onSelfIndexed',
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
const ctx = vm.createContext(sandbox);
|
||||
|
||||
const result = vm.runInContext(`
|
||||
Object.prototype.onProto = 'onProto';
|
||||
Object.defineProperty(Object.prototype, 'onProtoGetter', {
|
||||
get() {
|
||||
return 'onProtoGetter';
|
||||
},
|
||||
});
|
||||
Object.defineProperty(Object.prototype, 2, {
|
||||
value: 'onProtoIndexed',
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
const resultHasOwn = {
|
||||
onSelf: Object.hasOwn(this, 'onSelf'),
|
||||
onSelfGetter: Object.hasOwn(this, 'onSelfGetter'),
|
||||
onSelfIndexed: Object.hasOwn(this, 1),
|
||||
onProto: Object.hasOwn(this, 'onProto'),
|
||||
onProtoGetter: Object.hasOwn(this, 'onProtoGetter'),
|
||||
onProtoIndexed: Object.hasOwn(this, 2),
|
||||
};
|
||||
|
||||
const getDesc = (prop) => Object.getOwnPropertyDescriptor(this, prop);
|
||||
const resultDesc = {
|
||||
onSelf: getDesc('onSelf'),
|
||||
onSelfGetter: getDesc('onSelfGetter'),
|
||||
onSelfIndexed: getDesc(1),
|
||||
onProto: getDesc('onProto'),
|
||||
onProtoGetter: getDesc('onProtoGetter'),
|
||||
onProtoIndexed: getDesc(2),
|
||||
};
|
||||
({
|
||||
resultHasOwn,
|
||||
resultDesc,
|
||||
});
|
||||
`, ctx);
|
||||
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
assert.deepEqual(result, {
|
||||
resultHasOwn: {
|
||||
onSelf: true,
|
||||
onSelfGetter: true,
|
||||
onSelfIndexed: true,
|
||||
onProto: false,
|
||||
onProtoGetter: false,
|
||||
onProtoIndexed: false,
|
||||
},
|
||||
resultDesc: {
|
||||
onSelf: { value: 'onSelf', writable: true, enumerable: true, configurable: true },
|
||||
onSelfGetter: { get: onSelfGetter, set: undefined, enumerable: false, configurable: false },
|
||||
onSelfIndexed: { value: 'onSelfIndexed', writable: false, enumerable: false, configurable: true },
|
||||
onProto: undefined,
|
||||
onProtoGetter: undefined,
|
||||
onProtoIndexed: undefined,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user