Sept 19 TC39 Meeting Notes

David Bruant bruant.d at gmail.com
Fri Sep 28 04:20:36 PDT 2012


Thanks Rick for the notes (and everyone who contributed, I see several
colors)

Le 28/09/2012 03:00, Rick Waldron a écrit :
> # Proxy
> (Presented by Tom Van Cutsem, Free University of Brussels)
>
> ## Revokable Proxies 
>
> (...)
>
> Question as to whether we really need two kinds of proxies.
> BE: yes, non-revokable proxies have less trap overhead (no null-check)
I think it's possible to implement both without any overhead.
TVC suggested below that a revoked proxy is equivalent to a proxy with
all traps unconditionally throwing; well, a proxy, when revoke could
drop its target and change its handler on revokation.

A proxy can be modelled as {target, handler}. Both handler and target
are set at proxy creation and can't be changed arbitrarily by JS code.
We can model revocation as a capability that enables to change in one
operation both target to null and handler to a built-in handler which
throws on any operation. (it remains impossible to change target and
handler arbitrarily in JS code)
Modeled and implemented this way, there is no need for a null check.
When trapping, the revoked target (null) is passed to the handler trap,
which doesn't care since it throws regardless of the target value.
In that model, both type of proxies are just the same type and are as
efficient. No need for a null check before trapping. Just trap with the
current value and only provide to JS-land the capability to change the
target (only to a null value) through revokation.

> Discussion about whether revokable proxies introduce new ways for
> interceptable operations to behave.
>
> WH: Not sure about this as a feature, w/r to future hostility...
> -  eg. if "===" would trap to the handler how does this work with that?
>
> MM: trapping "===" would be a significant change on its own,
> independent of revokable proxies
>
> TVC: The only type test that is affected is typeof: once the proxy is
> revoked, it drops references to its target and its handler, so it can
> no longer forward the typeof test to its target
>
> BE: It remembers "function" or "object"
> TVC: right
Arguably, a revoked proxy could throw on === or typeof too.
It's already allowed to arbitrarily throw on [[Get]], [[Put]], 'in',
for-in/of loops, Object.getPrototypeOf, etc. It's not that big of a
stretch to throw on typeof or === even though these aren't trappable.
Unconditionally trapping on any operation on the object is future-proof.

> (...)
> WH: So, a frozen object can "unfreeze" itself?
>
> MM: No
>
> WH: An object that is frozen can later refuse that its frozen
> Concern about trapping isFrozen etc.: these tests are no longer stable.
> MM: but are still fail-stop. The integrity guarantee (i.e. that it
> always returns a correct answer) is more important than the
> availability guarantee (i.e. that it always returns an answer)
I agree.
If it's proven that the availability guarantee really matters in some
cases, I think a lot of things need to be re-designed in the proxy API.
How much does it matter?

> Alternative to trapping isFrozen etc.: cache stable outcome of certain
> operations in the proxy, and afterwards no longer trap.
>
> STH: After the first time isfrozen is true, mark to no longer call.
>
> AWB: would preclude valid use cases that e.g. want to log all
> requested isFrozen operations.
I agree. Proxies are a tool a virtualization. Restricting the way
proxies proxy through invariant checking is one thing, but preventing
from proxying seems to be a step too far in my opinion.

(...)
> **Conclusion/Resolution**
> - we want revocable proxies
> - further discussion is needed on revoking frozen objects, either via
> revocable proxies or via traps
    var t = Object.freeze({s: a300MbString});
    var {revoke, proxy} = Proxy.revokable(t, {});
    revoke();
    proxy.s; // ?

If the result is the long string because t is frozen, then it defeats
the purpose of why revokation is being introduced in the first place
(see TVC's problem description).


>
> ## Proxy and Private Names
>
> TVC: We don't want Proxy to inadvertently leak private name properties.
>
> In Redmond, we discussed that we would seperate string properties and
> private name properties into separate traps.
>
> Later determined that this would become cumbersome.
>
> Proposing to add a third argument to the Proxy constructor:
> a "whitelist" of private name properties that are allowed to be trapped.
>
> WH: unique vs private names?
> STH: The primary purpose of Names is to avoid name clash and
> non-forgeable. Uniques should be reflected, private: not.
>
> WH: What makes them non-forgeable
>
> STH: They are objects
I think it was Tom who suggested in a post that symbols (I'll do my best
to use the new terminology!) are more non-forgeable strings than
non-forgeable objects. Symbols should not be proxyable. Their only
important attribute is their identity, so proxying them would be absurd.
I think it should be considered to have symboles typeof to be "string"
instead of "object", or maybe something completely new, but for sure,
they are not objects.

>
> DH: And are as non-forgeable as objects, 
>
> WH: Why do we need both? Unique, Private?
>
> AWB: They are both useful
>
> STH: Unique names give you actual unforgeability
>
> MM: as opposed to the "unguessability" of randomly chosen strings
>
> DH: About the whitelist, instead of _requiring_ a WeakSet,  can it be
> anything that can be passed to a WeakSet, like an Array?
>
> MM: Should probably use a WeakMap...
Why so? I agree on the "weak", but it seems we want the whitelist to be
a set. The only operation on the whitelist internally is "has". It's
useful if JS code can "add" and "remove" elements. It looks like the
contract of a set, doesn't it?

>
> EA: An object that has a method that takes the public name string and
> returns the private name object, if you have access to that, you can
> extract the private data. 
>
> STH: Erik is right, but it a
>
> MM: if we don't drop the .public property, don't need the whitelist
> but instead just the resolvePrivateName trap. If we stick with the
> whitelist, don't pass the .public property to the resolvePrivateName trap
>
> TVC: Why is it a WeakSet? Because we dont want someone to provide
> their own collection that can extract the private data.
>
> TVC: Why is there a resolvePrivateName trap? Say an operation is
> performed on a proxy involving a private name, and the proxy doesn't
> know this private name. Two reasonable options: 1) forward to target,
> i dont see results, I dont care. OR 2) throw exception. A policy
> decision to be made by the handler: when working on a private name
> that we dont know about, forward or throw?
>
> DH: Should champions take this offline?
>
> STH: It's pretty important and could mean a significant simplification.
>
> WH: Would like to get rid of the public/private property flags
>
> DH: for notational convenience, would be great if one could pass an
> array literal as 3rd arg
> TVC: could specify that if 3rd arg is an array-like, we copy its
> elements into a built-in WeakSet
> WH: that would be confusing: names later added to the array-like won't
> get added to the internal WeakSet
>
>
> AWB: Not clear how using a built-in WeakSet will protect, what if it's
> been redefined? Are WeakSet methods non-writable?
> TVC: we need to specify that the proxy calls the original/intrinsic
> WeakSet.prototype.get method.
Typof. I think you meant WeakSet.prototype.has (WeakSets have no "get").

>
> STH/LH/RW: Will need to spec WeakSet
>
> **Conclusion/Resolution**
> Yes to third arg for whitelist, pending details to be worked out by
> Proxy champions.
>
> Expect to remove the "public" part of private names. 
>
>
> ## WeakSet 
>
> DH: Clear that we need WeakSet to match WeakMap (Set and Map)
>
> AWB: Need to assure that WeakMap and WeakSet are not redefined?
Application code can enforce that if necessary:

    Object.defineProperty(this, 'WeakSet', {configurable: false,
writable: false});

> RW: Use cases in node programs where I'm using WeakMap made it
> apparent that it _is_ possible to leak via redefinition.
The first code that runs in a fresh ECMAScript environment is the one in
charge of deciding what can be redefined and what cannot.
The first code that runs decides of the security policy. If it's a
defender, it can freeze built-ins. If it's an attacker, it can redefine
built-ins in harmful way.
If no choice is made by the first code, the next piece of code decides
and so on.

In my opinion, the structure of any secure and reliable JavaScript (ES5)
application should be like:
1) enhance environment (polyfills, libraries, etc.)
2) freeze built-ins (via initSES.js or equivalent)
3) application code

ES6 Modules may change this. I haven't given much thoughts of how it does.

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120928/b6f27b15/attachment-0001.html>


More information about the es-discuss mailing list