Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: add vm proto property lookup test #54606

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions test/parallel/test-vm-global-property-enumerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const assert = require('assert');

const cases = [
{
get 1() {
return 'value';
},
get key() {
return 'value';
},
Expand All @@ -15,28 +18,39 @@ const cases = [
// Intentionally single setter.
// eslint-disable-next-line accessor-pairs
set key(value) {},
// eslint-disable-next-line accessor-pairs
set 1(value) {},
},
{},
{
key: 'value',
1: 'value',
},
(new class GetterObject {
get key() {
return 'value';
}
get 1() {
return 'value';
}
}()),
(new class SetterObject {
// Intentionally single setter.
// eslint-disable-next-line accessor-pairs
set key(value) {
// noop
}
// eslint-disable-next-line accessor-pairs
set 1(value) {
// noop
}
}()),
[],
[['key', 'value']],
{
__proto__: {
key: 'value',
1: 'value',
},
},
];
Expand Down
224 changes: 193 additions & 31 deletions test/parallel/test-vm-global-property-prototype.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,160 @@ require('../common');
const assert = require('assert');
const vm = require('vm');

const outerProto = {
onOuterProto: 'onOuterProto',
bothProto: 'onOuterProto',
};
function onOuterProtoGetter() {
return 'onOuterProtoGetter';
}
Object.defineProperties(outerProto, {
onOuterProtoGetter: {
get: onOuterProtoGetter,
},
bothProtoGetter: {
get: onOuterProtoGetter,
},
// outer proto indexed
0: {
value: 'onOuterProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
// both proto indexed
3: {
value: 'onOuterProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
});

// Creating a new intermediate proto to mimic the
// window -> Window.prototype -> EventTarget.prototype chain in JSDom.
const sandboxProto = {
__proto__: outerProto,
};

const sandbox = {
__proto__: sandboxProto,
onSelf: 'onSelf',
};

function onSelfGetter() {
return 'onSelfGetter';
}

Object.defineProperty(sandbox, 'onSelfGetter', {
get: onSelfGetter,
});

Object.defineProperty(sandbox, 1, {
value: 'onSelfIndexed',
writable: false,
enumerable: false,
configurable: true,
Object.defineProperties(sandbox, {
onSelfGetter: {
get: onSelfGetter,
},
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.prototype.onInnerProto = 'onInnerProto';
Object.defineProperties(Object.prototype, {
onInnerProtoGetter: {
get() {
return 'onInnerProtoGetter';
},
},
2: {
value: 'onInnerProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
});
Object.defineProperty(Object.prototype, 2, {
value: 'onProtoIndexed',
writable: false,
enumerable: false,
configurable: true,

// Override outer proto properties
Object.prototype.bothProto = 'onInnerProto';
Object.defineProperties(Object.prototype, {
bothProtoGetter: {
get() {
return 'onInnerProtoGetter';
},
},
// outer proto indexed
3: {
value: 'onInnerProtoIndexed',
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),
onOuterProto: Object.hasOwn(this, 'onOuterProto'),
onOuterProtoGetter: Object.hasOwn(this, 'onOuterProtoGetter'),
onOuterProtoIndexed: Object.hasOwn(this, 0),
onInnerProto: Object.hasOwn(this, 'onInnerProto'),
onInnerProtoGetter: Object.hasOwn(this, 'onInnerProtoGetter'),
onInnerProtoIndexed: Object.hasOwn(this, 2),
bothProto: Object.hasOwn(this, 'bothProto'),
bothProtoGetter: Object.hasOwn(this, 'bothProtoGetter'),
bothProtoIndexed: Object.hasOwn(this, 3),
};

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),
onOuterProto: getDesc('onOuterProto'),
onOuterProtoGetter: getDesc('onOuterProtoGetter'),
onOuterProtoIndexed: getDesc(0),
onInnerProto: getDesc('onInnerProto'),
onInnerProtoGetter: getDesc('onInnerProtoGetter'),
onInnerProtoIndexed: getDesc(2),
bothProto: getDesc('bothProto'),
bothProtoGetter: getDesc('bothProtoGetter'),
bothProtoIndexed: getDesc(3),
};
const resultIn = {
onSelf: 'onSelf' in this,
onSelfGetter: 'onSelfGetter' in this,
onSelfIndexed: 1 in this,
onOuterProto: 'onOuterProto' in this,
onOuterProtoGetter: 'onOuterProtoGetter' in this,
onOuterProtoIndexed: 0 in this,
onInnerProto: 'onInnerProto' in this,
onInnerProtoGetter: 'onInnerProtoGetter' in this,
onInnerProtoIndexed: 2 in this,
bothProto: 'bothProto' in this,
bothProtoGetter: 'bothProtoGetter' in this,
bothProtoIndexed: 3 in this,
};
const resultValue = {
onSelf: this.onSelf,
onSelfGetter: this.onSelfGetter,
onSelfIndexed: this[1],
onOuterProto: this.onOuterProto,
onOuterProtoGetter: this.onOuterProtoGetter,
onOuterProtoIndexed: this[0],
onInnerProto: this.onInnerProto,
onInnerProtoGetter: this.onInnerProtoGetter,
onInnerProtoIndexed: this[2],
bothProto: this.bothProto,
bothProtoGetter: this.bothProtoGetter,
bothProtoIndexed: this[3],
};
({
resultHasOwn,
resultDesc,
resultIn,
resultValue,
});
`, ctx);

Expand All @@ -68,16 +166,80 @@ assert.deepEqual(result, {
onSelf: true,
onSelfGetter: true,
onSelfIndexed: true,
onProto: false,
onProtoGetter: false,
onProtoIndexed: false,

// All prototype properties are not own properties.
onOuterProto: false,
onOuterProtoGetter: false,
onOuterProtoIndexed: false,
onInnerProto: false,
onInnerProtoGetter: false,
onInnerProtoIndexed: false,
bothProto: false,
bothProtoGetter: false,
bothProtoIndexed: 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,

// All prototype properties are not own properties.
onOuterProto: undefined,
onOuterProtoGetter: undefined,
onOuterProtoIndexed: undefined,
onInnerProto: undefined,
onInnerProtoGetter: undefined,
onInnerProtoIndexed: undefined,
bothProto: undefined,
bothProtoGetter: undefined,
bothProtoIndexed: undefined,
},
resultIn: {
onSelf: true,
onSelfGetter: true,
onSelfIndexed: true,

// Only properties exist on inner prototype chain will be looked up
// on `in` operator. In the VM Context, the prototype chain will be like:
// ```
// Object
// ^
// | prototype
// InnerPrototype
// ^
// | prototype
// globalThis
// ```
// Outer prototype is not in the inner global object prototype chain and it
// will not be looked up on `in` operator.
onOuterProto: false,
onOuterProtoGetter: false,
onOuterProtoIndexed: false,
onInnerProto: true,
onInnerProtoGetter: true,
onInnerProtoIndexed: true,
bothProto: true,
bothProtoGetter: true,
bothProtoIndexed: true,
},
resultValue: {
onSelf: 'onSelf',
onSelfGetter: 'onSelfGetter',
onSelfIndexed: 'onSelfIndexed',

// FIXME(legendecas): The outer prototype is not observable from the inner
// vm. Allowing property getter on the outer prototype can be confusing
// comparing to the normal JavaScript objects.
// Additionally, this may expose unexpected properties on the outer
// prototype chain, like polyfills, to the vm context.
onOuterProto: 'onOuterProto',
onOuterProtoGetter: 'onOuterProtoGetter',
onOuterProtoIndexed: 'onOuterProtoIndexed',
onInnerProto: 'onInnerProto',
onInnerProtoGetter: 'onInnerProtoGetter',
onInnerProtoIndexed: 'onInnerProtoIndexed',
bothProto: 'onOuterProto',
bothProtoGetter: 'onOuterProtoGetter',
bothProtoIndexed: 'onOuterProtoIndexed',
},
});
Loading