Skip to content

Commit 0b07f2c

Browse files
authored
vm: fix property queries for proxy sandboxes
Signed-off-by: Brian Meek <55990082+brianathere@users.noreply.github.com> PR-URL: #63742 Fixes: #63739 Refs: #63549 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent da00166 commit 0b07f2c

2 files changed

Lines changed: 78 additions & 4 deletions

File tree

src/node_contextify.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,13 @@ Intercepted ContextifyContext::PropertyQueryCallback(
493493

494494
PropertyAttribute attr;
495495

496-
Maybe<bool> maybe_has = sandbox->HasRealNamedProperty(context, property);
496+
Maybe<bool> maybe_has = sandbox->HasOwnProperty(context, property);
497497
if (maybe_has.IsNothing()) {
498498
return Intercepted::kNo;
499499
} else if (maybe_has.FromJust()) {
500-
Maybe<PropertyAttribute> maybe_attr =
501-
sandbox->GetRealNamedPropertyAttributes(context, property);
502-
if (!maybe_attr.To(&attr)) {
500+
Maybe<bool> maybe_attr =
501+
sandbox->GetPropertyAttributes(context, property, &attr);
502+
if (!maybe_attr.FromMaybe(false)) {
503503
return Intercepted::kNo;
504504
}
505505
args.GetReturnValue().Set(attr);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('node:assert');
5+
const vm = require('node:vm');
6+
7+
// This test ensures that Proxy-backed vm sandboxes report own properties
8+
// consistently across descriptor and membership queries.
9+
10+
const sandbox = new Proxy({}, {});
11+
const ctx = vm.createContext(sandbox);
12+
13+
vm.runInContext(`
14+
Object.defineProperty(this, 'foo', {
15+
value: 42,
16+
writable: true,
17+
enumerable: true,
18+
configurable: true,
19+
});
20+
Object.defineProperty(this, 'hidden', {
21+
value: 1,
22+
enumerable: false,
23+
configurable: true,
24+
});
25+
Object.defineProperty(this, 'readonly', {
26+
value: 2,
27+
writable: false,
28+
enumerable: true,
29+
configurable: true,
30+
});
31+
`, ctx);
32+
33+
const result = vm.runInContext(`({
34+
value: foo,
35+
descriptor: Object.getOwnPropertyDescriptor(globalThis, 'foo'),
36+
ownNamesIncludes: Object.getOwnPropertyNames(globalThis).includes('foo'),
37+
hasOwnProperty:
38+
Object.prototype.hasOwnProperty.call(globalThis, 'foo'),
39+
objectHasOwn: Object.hasOwn(globalThis, 'foo'),
40+
inGlobalThis: 'foo' in globalThis,
41+
reflectHas: Reflect.has(globalThis, 'foo'),
42+
keysIncludesFoo: Object.keys(globalThis).includes('foo'),
43+
keysIncludesHidden: Object.keys(globalThis).includes('hidden'),
44+
hiddenIsEnumerable:
45+
Object.prototype.propertyIsEnumerable.call(globalThis, 'hidden'),
46+
readonlyDescriptor:
47+
Object.getOwnPropertyDescriptor(globalThis, 'readonly'),
48+
hasOwnToString: Object.hasOwn(globalThis, 'toString'),
49+
toStringInGlobalThis: 'toString' in globalThis,
50+
})`, ctx);
51+
52+
assert.strictEqual(result.value, 42);
53+
assert.deepStrictEqual({ ...result.descriptor }, {
54+
value: 42,
55+
writable: true,
56+
enumerable: true,
57+
configurable: true,
58+
});
59+
assert.strictEqual(result.ownNamesIncludes, true);
60+
assert.strictEqual(result.hasOwnProperty, true);
61+
assert.strictEqual(result.objectHasOwn, true);
62+
assert.strictEqual(result.inGlobalThis, true);
63+
assert.strictEqual(result.reflectHas, true);
64+
assert.strictEqual(result.keysIncludesFoo, true);
65+
assert.strictEqual(result.keysIncludesHidden, false);
66+
assert.strictEqual(result.hiddenIsEnumerable, false);
67+
assert.deepStrictEqual({ ...result.readonlyDescriptor }, {
68+
value: 2,
69+
writable: false,
70+
enumerable: true,
71+
configurable: true,
72+
});
73+
assert.strictEqual(result.hasOwnToString, false);
74+
assert.strictEqual(result.toStringInGlobalThis, true);

0 commit comments

Comments
 (0)