Object.freezing proxies should freeze or throw?

Tom Van Cutsem tomvc.be at gmail.com
Wed Aug 10 08:50:37 UTC 2016

Thanks Claude for your careful review, and for trying to articulate a more
general principle behind the invariant checks. The lack of such crisp
principles makes it (too) difficult to verify whether all necessary checks
are in place.

To clarify, in the case of "update" MOP operations such as defineProperty
and deleteProperty, your "state B" (the observable state of the target),
presumably is the state of the target *after* the proxy trap has executed,
i.e. state B should already reflect the update.

Both the original issue and your new test case with deleteProperty are
cases where the proxy pretends to have altered the target but has in fact
not. In a later interaction, the proxy reverts to the original state. This
violates a client's expectations about when state transitions occur.

Interestingly, the opposite problem, where a proxy does alter the target as
requested, but then reports that the update failed, is allowed, even though
this technically also violates a client's expectations about what state
transitions have occurred. But a failed update leads to a TypeError anyway.

At this point, we should probably iron out the details of the fix in a
GitHub issue or on bugs.ecmascript.org.


2016-08-09 14:44 GMT+02:00 Claude Pache <claude.pache at gmail.com>:

> Given a Proxy that pretends to be in state A while its target is
> observably in state B, and assuming that the target satisfies the
> Invariants of the Essential Internal Methods [], I claim that, in
> order to force the Proxy to satisfy those Invariants, it is necessary and
> sufficient to check that the two following conditions hold:
> * it is legal for an object to pass from state A to state B; and,
> * it is legal for an object to pass from state B to state A.
> []: https://tc39.github.io/ecma262/#sec-invariants-of-
> the-essential-internal-methods
> Because I am too lazy to write the proof just now, I cowardly leave it as
> an exercice to the reader. Meanwhile, that principle may be used to audit
> the robustness of the Proxy specification. I have found the following bug
> in Proxy.[[Delete]]() by applying the above principle to:
> * state A: nonexistent property on a nonextensible object;
> * state B: existent own property on a nonextensible object.
> Resurrection of a successfully deleted property on a nonextensible object:
> ```js
> var target = Object.preventExtensions({ x: 1 })
> var proxy = new Proxy(target, {
>     deleteProperty() { return true }
> })
> Object.isExtensible(proxy) // false
> delete proxy.x // true
> proxy.hasOwnProperty('x') // true
> ```
> After a first scan, I haven't found other bugs in the essential methods of
> Proxy, than that one and the missing nonconfigurable-but-writable check in
> [[GetOwnPropertyDescriptor]] and [[DefineOwnProperty]] already mentioned in
> that thread.
> I plan to propose a minimal patch (i.e., just adding the missing checks)
> in a few days.
> —Claude
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160810/81a60350/attachment.html>

More information about the es-discuss mailing list