Why we need to clean up __proto__

Lasse Reichstein reichsteinatwork at gmail.com
Wed Dec 28 17:26:57 PST 2011


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
>


More information about the es-discuss mailing list