Why we need to clean up __proto__

Mark S. Miller erights at google.com
Wed Dec 28 17:36:35 PST 2011


[change of Subject: as this reply starts the promised thread]


Hi Lasse, good. That is the direction Dave Herman suggested and which I
also find attractive. I have elaborated it at <
http://wiki.ecmascript.org/doku.php?id=strawman:magic_proto_property>,
which I've also placed on the Agenda for the January EcmaScript meeting.

The most surprising punchline is in requirement #4:

Object.create(null), creating an object that does not inherit from
Object.prototype, also creates an object that does not inherit it’s
__proto__, even if that property has not been deleted. With this change,
objects-as-stringmaps for objects created by Object.create(null) would
avoid the __proto__ hazard, even in contexts where
Object.prototype.__proto__ has not been deleted. (FF already acts this way,
so my previous message was wrong in claiming that Object.create(null) fails
to avoid this platform on all non-IE browsers.)


Comments on this proposal appreciated.

On Wed, Dec 28, 2011 at 5:26 PM, Lasse Reichstein <
reichsteinatwork at gmail.com> wrote:

> The biggest problem with __proto__, as I see it, isn't that you can
> hit it accidentally, but that even if you know what you are doing, you
> can't avoid it (and have to do expensive workarounds).
>
> It obviously depends on the implementation. In Mozilla
> Firefox/*Monkey, __proto__ is an inherited accessor on
> Object.prototype (just as __define[SG]etter__). It's not an
> own-property and you can shadow it.
>
> In Chrome/V8, it's an artificial own property on every object, and it
> can't be removed, shadowed or ignored. It tries to emulate Safari's
> original implementation, but probably fails some details (as your
> tests show, they aren't the same).
>
> I like the Firefox way much better, both as a user and as an
> implementor. Since we probably can't get rid of __proto__ totally, I
> would cheer if implementations would change to the Mozilla way.
>
> /L 'entirely my personal opinion'.
>
> On Tue, Dec 27, 2011 at 3:53 AM, Mark S. Miller <erights at google.com>
> wrote:
> > Or, "Even Crock's Code Doesn't Overcome All The Bad Parts."
> >
> >
> > In this message, I explain why I believe we need to clean up __proto__.
> I'll
> > start a separate thread on how to clean it up -- which is just my
> > documenting a suggestion from Dave Herman.
> >
> >
> > From
> > <
> http://eleventyone.done.hu/OReilly.JavaScript.The.Good.Parts.May.2008.pdf>
> > PDF page 119
> >
> >    that.on = function (type, ....) {
> >       ....
> >       var registry = {};
> >       ....
> >       if (registry.hasOwnProperty(type)) {
> >           registry[type].push(handler);
> >       } else {
> >           registry[type] = [handler];
> >       }
> >       ....
> >   };
> >
> > This "registry" is a classic use of an object as a string-to-value
> map. Note
> > that the "type" parameter comes in from the client of the abstraction.
> The
> > only validation performed on it is the "hasOwnProperty" check above.
> > Elsewhere Crock points out that this hasOwnProperty check does not work
> if
> > "hasOwnProperty" itself is ever used as a key, and so we should instead
> say:
> >
> >       if (Object.prototype.hasOwnProperty.call(registry, type)) {
> >
> > This still doesn't yet work on most actual browsers for a reason
> explained
> > below.
> >
> >
> >
> > <aside on why ES5 does not really help>
> >
> > Going beyond "Good Parts", EcmaScript 5 gives us two new opportunities to
> > clean up this code further.
> >
> > 1) We can protect ourselves from other code monkey patching
> > away Object.prototype.hasOwnProperty
> > and/or Object.prototype.hasOwnProperty.call by using
> > <
> http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming>
> > at initialization time, assuming that this module gets to initialize
> itself
> > before such monkey patching may have occurred:
> >
> >   var bind = Function.prototype.bind;
> >   var uncurryThis = bind.bind(bind.call);
> >
> >   var hopFn = uncurryThis({}.hasOwnProperty);
> >
> > So that we can say
> >
> >       if (hopFn(registry, type)) {
> >
> > 2) We can replace the initialization of "registry" with
> >
> >       var registry = Object.create(null);
> >
> > or, if we wish the same protection from post-initialization monkey
> patching
> >
> >   var create = Object.create;
> >   ...
> >       var registry = create(null);
> >
> > It turns out that neither of these additional ES5-based paranoid steps
> helps
> > with the worst problem remaining with Crock's corrected code. Likewise,
> > nothing so far proposed for ES-next would help, except for Dave Herman's
> > suggestion which I will write up shortly.
> >
> > </aside on why ES5 does not really help>
> >
> >
> >
> > As you've probably already guessed from the title of this email, the
> problem
> > occurs on most platforms when the function is called with an argument of
> > "__proto__". Since we do a "hasOwnProperty" check first, the way in which
> > this goes wrong depends on the platform. Evaluating
> >
> >     [{}.hasOwnProperty('__proto__'),
> > {}.__proto__.hasOwnProperty('__proto__')]
> >
> > on various browsers gives:
> >
> > false,false       // Chrome
> > true,true         // WebKit Nightly
> > false,true        // FF Nightly
> > false,false       // Opera 12 alpha
> > throws TypeError  // IE10 Preview 2
> >
> > Since IE doesn't treat "__proto__" as special magic, no problem there.
> > WebKit Nightly will take the branch that happens to fail safe here, but
> only
> > for the reason that there's no "Object.prototype.push". All we can say is
> > that we got lucky this time. When Chrome, FF, and Opera evaluate
> >
> >       registry['__proto__'] = [handler];
> >
> > they change registry to inherit from [handler] rather than
> Object.prototype.
> > WebKit would do the same if it had executed this line.
> >
> > Think this exercise is academic and doesn't arise in real systems?  As
> > observed at
> > <
> http://www.google.com/support/forum/p/Google+Docs/thread?tid=0cd4a00bd4aef9e4
> >,
> > until recently, on all non-IE browsers, if you typed "__proto__" at the
> > beginning of a new Google Doc, your Google Doc would hang. This was
> tracked
> > down to such a buggy use of an object as a string map. (To avoid such
> > problems, Caja is shifting to using
> > <
> http://code.google.com/p/es-lab/source/browse/trunk/src/ses/StringMap.js>,
> > which does seem safe on all platforms.)
> >
> >
> > --
> >     Cheers,
> >     --MarkM
> >
> > _______________________________________________
> > es-discuss mailing list
> > es-discuss at mozilla.org
> > https://mail.mozilla.org/listinfo/es-discuss
> >
>



-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111228/be08b7a3/attachment.html>


More information about the es-discuss mailing list