src: don't overwrite non-writable vm globals
Check that the property doesn't have the read-only flag set before overwriting it. This is Ben Noordhuis previous commit, but keeping is_contextual_store. is_contextual_store describes whether this.foo = 42 or foo = 42 was called. The second is contextual and will fail in strict mode if foo is used without declaration. Therefore only do an early return if it is a contextual store. In particular, don't do an early return for Object.defineProperty(this, ...). Fixes: https://github.com/nodejs/node/issues/10223 Refs: https://github.com/nodejs/node/pull/10227 PR-URL: https://github.com/nodejs/node/pull/11109 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
This commit is contained in:
parent
0101d77a22
commit
e116cbe320
@ -383,19 +383,28 @@ class ContextifyContext {
|
|||||||
if (ctx->context_.IsEmpty())
|
if (ctx->context_.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto attributes = PropertyAttribute::None;
|
||||||
bool is_declared =
|
bool is_declared =
|
||||||
ctx->global_proxy()->HasRealNamedProperty(ctx->context(),
|
ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(),
|
||||||
property).FromJust();
|
property)
|
||||||
|
.To(&attributes);
|
||||||
|
bool read_only =
|
||||||
|
static_cast<int>(attributes) &
|
||||||
|
static_cast<int>(PropertyAttribute::ReadOnly);
|
||||||
|
|
||||||
|
if (is_declared && read_only)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// true for x = 5
|
||||||
|
// false for this.x = 5
|
||||||
|
// false for Object.defineProperty(this, 'foo', ...)
|
||||||
|
// false for vmResult.x = 5 where vmResult = vm.runInContext();
|
||||||
bool is_contextual_store = ctx->global_proxy() != args.This();
|
bool is_contextual_store = ctx->global_proxy() != args.This();
|
||||||
|
|
||||||
bool set_property_will_throw =
|
if (!is_declared && args.ShouldThrowOnError() && is_contextual_store)
|
||||||
args.ShouldThrowOnError() &&
|
return;
|
||||||
!is_declared &&
|
|
||||||
is_contextual_store;
|
|
||||||
|
|
||||||
if (!set_property_will_throw) {
|
ctx->sandbox()->Set(property, value);
|
||||||
ctx->sandbox()->Set(property, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,3 +75,16 @@ assert.throws(function() {
|
|||||||
// https://github.com/nodejs/node/issues/6158
|
// https://github.com/nodejs/node/issues/6158
|
||||||
ctx = new Proxy({}, {});
|
ctx = new Proxy({}, {});
|
||||||
assert.strictEqual(typeof vm.runInNewContext('String', ctx), 'function');
|
assert.strictEqual(typeof vm.runInNewContext('String', ctx), 'function');
|
||||||
|
|
||||||
|
// https://github.com/nodejs/node/issues/10223
|
||||||
|
ctx = vm.createContext();
|
||||||
|
vm.runInContext('Object.defineProperty(this, "x", { value: 42 })', ctx);
|
||||||
|
assert.strictEqual(ctx.x, 42);
|
||||||
|
assert.strictEqual(vm.runInContext('x', ctx), 42);
|
||||||
|
|
||||||
|
vm.runInContext('x = 0', ctx); // Does not throw but x...
|
||||||
|
assert.strictEqual(vm.runInContext('x', ctx), 42); // ...should be unaltered.
|
||||||
|
|
||||||
|
assert.throws(() => vm.runInContext('"use strict"; x = 0', ctx),
|
||||||
|
/Cannot assign to read only property 'x'/);
|
||||||
|
assert.strictEqual(vm.runInContext('x', ctx), 42);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user