Skip to content

Commit

Permalink
fix: rename to originalValue (#476)
Browse files Browse the repository at this point in the history
  • Loading branch information
erights authored Sep 27, 2020
1 parent e514a6e commit 54e0b0c
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 9 deletions.
8 changes: 7 additions & 1 deletion packages/ses/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ User-visible changes in SES:

## Next release

* When converting each of [these data properties](src/enablements.js) to
accessor properties, to suppress the
[override mistake](https://github.com/tc39/ecma262/pull/1320), we now
add to that accessor's getter an `originalValue` property to mark it
as alleging that it is emulating a data property whose original value
was that value.
* Fixes an exception thrown when calling `lockdown` after just importing
`ses/lockdown` in all environments.

Expand Down Expand Up @@ -38,7 +44,7 @@ User-visible changes in SES:
https://github.com/tc39/proposal-eventual-send.
* Corrects our fix for the override mistake, so that it correctly emulates
how assignment would work in the absence of the override mistake.
A property created by assignment will now be a writable, enumerable,
A property created by assignment will now be a writable, enumerable,
configurable data property, as it is for normal assignment.

## Release 0.10.0 (8-August-2020)
Expand Down
15 changes: 15 additions & 0 deletions packages/ses/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,21 @@ The compartment will call `execute` with:
method of third-party static module records to return promises, to support
top-level await.

### Imperfect emulation

JavaScript suffers from the so-called
[override mistake](https://web.archive.org/web/20141230041441/http://wiki.ecmascript.org/doku.php?id=strawman:fixing_override_mistake),
which prevents lockdown from *simply* hardening all the primordials. Rather,
for each of
[these data properties](src/enablements.js), we convert it to an accessor
property whose getter and setter emulate [a data property without the override
mistake](https://github.com/tc39/ecma262/pull/1320). For non-reflective code
the illusion is perfect. But reflective code sees that it is an accessor
rather than a data property. We add a `originalValue` property to the getter
of that accessor, letting reflective code know that a getter alleges that it
results from this transform, and what the original data value was. This enables
a form of cooperative emulation, where that code can decide whether to uphold
the illusion by pretending it sees the data property that would have been there.

## Bug Disclosure

Expand Down
18 changes: 12 additions & 6 deletions packages/ses/src/enable-property-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ function isObject(obj) {
*
* Because of lack of sufficient foresight at the time, ES5 unfortunately
* specified that a simple assignment to a non-existent property must fail if
* it would override a non-writable data property of the same name. In
* retrospect, this was a mistake, the so-called "override mistake". But it is
* now too late and we must live with the consequences.
* it would override an non-writable data property of the same name in the
* shadow of the prototype chain. In retrospect, this was a mistake, the
* so-called "override mistake". But it is now too late and we must live with
* the consequences.
*
* As a result, simply freezing an object to make it tamper proof has the
* unfortunate side effect of breaking previously correct code that is
Expand All @@ -47,7 +48,7 @@ function isObject(obj) {
* writing, this is the best we know how to do.
*
* To the getter of the accessor we add a property named
* `'originalDataPropertyValue'` whose value is, as it says, the value that the
* `'originalValue'` whose value is, as it says, the value that the
* data property had before being converted to an accessor property. We add
* this extra property to the getter for two reason:
*
Expand All @@ -63,7 +64,7 @@ function isObject(obj) {
* We enable a form of cooperative emulation, giving reflective code an
* opportunity to cooperate in upholding the illusion. When such cooperative
* reflective code sees an accessor property, where the accessor's getter
* has an `originalDataPropertyValue` property, it knows that the getter is
* has an `originalValue` property, it knows that the getter is
* alleging that it is the result of the `enablePropertyOverrides` conversion
* pattern, so it can decide to cooperatively "pretend" that it sees a data
* property with that value.
Expand All @@ -78,7 +79,12 @@ export default function enablePropertyOverrides(intrinsics) {
function getter() {
return value;
}
getter.originalDataPropertyValue = value;
defineProperty(getter, 'originalValue', {
value,
writable: false,
enumerable: false,
configurable: false,
});

function setter(newValue) {
if (obj === this) {
Expand Down
4 changes: 2 additions & 2 deletions packages/ses/test/frozen-primordials.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ test('check if override-protected primordials are frozen', t => {
lockdown();

// After removing the detachedProperties mechanism and without
// the originalDataPropertyValue mechanism, this test failed.
// the originalValue mechanism, this test failed.
t.ok(Object.isFrozen(Object.prototype.toString));

const desc = getOwnPropertyDescriptor(Object.prototype, 'toString');
t.equals(desc.get.originalDataPropertyValue, Object.prototype.toString);
t.equals(desc.get.originalValue, Object.prototype.toString);

t.end();
});

0 comments on commit 54e0b0c

Please sign in to comment.