-
Notifications
You must be signed in to change notification settings - Fork 0
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
Possible solution to override mistake without a new integrity trait #4
Comments
To clarify, this is unilaterally fixing the override mistake, just with mitigations for some observed in-the-wild reliance of the override mistake currently silently failing in sloppy mode? |
Correct.
Correct.
Incorrect. This fixes an assumption made in both sloppy and strict modes.
With the new override behavior, this code would change. Since the new built-ins don't have special behavior in |
If the override mistake can be fixed unilaterally that is ideal, but if it's not web compatible, we can still fix it without changing the object model I've suggested in the past. To summarize and simplify that suggestion, we would just have a new slot on ordinary objects, have a way to freeze and set that slot to true, and then I called it harden, but it could just be an argument to freeze: const o = Object.freeze({ x: 10 }, true);
// o is an object { [[AllowOverride]]: true, x: 10 }
const o2 = { __proto__: o };
// o has slot [[AllowOverride]] so the override mistake is disabled.
o2.x = 12; As this doesn't add any proxy traps it should be very simple to implement (just a bit on ordinary objects so it's extremely lightweight). |
@Jamesernator adding a new slot is effectively the equivalent of the overidable integrity trait we're suggesting. Why do you believe it wouldn't require a proxy trap? |
Because it adds no more power than if ordinary objects just had a private field, it would essentially just change the current check:
to:
Freezing would essentially be: function freezeWithOverride(o) {
// Prevent a communication channel if the object is already frozen
if (Object.isFrozen(o)) {
return;
}
if (#allowOverride in o) {
o.#allowOverride = true;
}
Object.freeze(o);
} |
The problem is that having no traps prevents a proxy the opportunity to reflect the state of the real target on its shadow target. Imagine the following simplified pattern that is common in membranes: const shadowToReal= new WeakMap();
const realToProxy = new WeakMap();
// Traps of the handler lookup the real target from the shadow in shadowToReal
// and reflect the shape of the real target onto the shadow as necessary to respect
// object invariants and according to any distortion that the membrane wants to apply.
const membraneHandler = {...};
const getProxyForTarget = (target) => {
let proxy = realToProxy.get(target);
if (proxy) return proxy;
// Approximation of creating a bare shadow object of the same "kind"
const shadow = typeof target === 'function' ?
function() {} :
Array.isArray(target) ?
[] :
{ __proto__: null };
shadowToReal.set(shadow, target);
proxy = new Proxy(shadow, membraneHandler);
realToProxy.set(target, proxy);
return proxy;
}; Without "is overridable" and "make overridable" proxy traps, the following can't work: const someTarget = {};
const proxy = getProxyForTarget(someTarget);
freezeWithOverride(someTarget);
stampPrivateField(proxy); // This should fail
const someOtherTarget = {};
const otherProxy = getProxyForTarget(someOtherTarget);
freezeWithOverride(otherProxy); // If distortions allow
stampPrivateField(someOtherTarget); // Should now fail |
I wasn't suggesting that the trap for preventing private field stamping can be removed. That is separate as it is actually a fundamental capability for objects. Unlike the override mistake, there is no proxy you can write to emulate such behaviour. Though yes |
Ugh sorry I got my overrides mixed up. But I believe the same argument holds for the assign override mistake. I'll follow up with some examples. |
Based on the bug found in tc39/ecma262#1320 (comment):
o.foo = v
o
with{ value: v, enumerable: true, writable: true, configurable: true }
(like it's defining a new property without extending the parent)delete
statement when runninggetRawTag(new Uint8Array(0))
.Object.prototype.toString()
special cases with typed arrays,DataView
,ArrayBuffer
,Map
,WeakMap
,Set
,WeakSet
,Promise
, etc.value[Symbol.toStringTag] = undefined
, we must fix various builtins to still return the expected[object Foo]
values.isTypedArray
,isArrayBuffer
, etc, functions directly, and thegetTag
function indirectly by ensuring a few feature checks don't fail and cause a incomplete impl ofgetTag
to be used.The text was updated successfully, but these errors were encountered: