Must built-in prototypes also be valid instances? (Was: Why DataView.prototype object's [[Class]] is "Object"?)

Brendan Eich brendan at mozilla.com
Mon Oct 1 21:02:31 PDT 2012


Mark S. Miller wrote:
> On Mon, Oct 1, 2012 at 8:17 PM, Brendan Eich <brendan at mozilla.com 
> <mailto:brendan at mozilla.com>> wrote:
>
>     Mark S. Miller wrote:
>
>         Regarding the integrity of original
>         Object.prototype.toString.call as a branding mechanism, I
>         agree we need a new more general branding mechanism. WeakMaps
>         and Symbols both give us a place to hang this, but we need a
>         concrete proposal. The proposal should work both with builtins
>         and with classes. If a better branding proposal waits till
>         ES7, then we need to preserve integrity of original
>         Object.prototype.toString.call as a branding mechanism through
>         ES6. If this is preserved through ES6, then it probably
>         becomes too entrenched to consider retiring.
>
>         Were there other questions for me that I missed?
>
>
>     Yes. Should (per the latest draft, 15.2.4.2
>     Object.prototype.toString) the following names:
>
>
>     "Arguments", "Array", "Boolean", "Date", "Error", "Function",
>     "JSON", "Math", "Number", "Object", "RegExp", or "String"
>
>     and "Object" (per Allen here), and only these names, be prefixed
>     with "~" when returned via [[Get]](@@toStringTag) where
>     @@toStringTag denotes a spec-internal (implementation-internal)
>     symbol?
>
>
> The "~" looks very ugly to me. As I state above, I would rather we 
> invent a more general branding mechanism and then stop making this 
> requirement on original Object.prototype.toString.call.

Agreed, let's do it.

> Relaxing this requirement would still technically be a breaking change 
> from ES5 so we need to be cautious. But I bet we can get away with it 
> if we do it by ES6. By ES7 it will probably be too late.

I doubt it'll be too late. In part I am skeptical because I do not 
believe any engine actually prevents host objects from spoofing the 13 
class names listed above. Anyone know of an engine that does?

Words on paper still carry force but they do not necessarily have prompt 
effects, or any effects. It depends on the people reading them and 
implementing, and trying to follow the rules. Those people are much more 
likely to audit their (closed, per release, typically) set of host 
objects and fix any spoofers.

>     The idea is to uphold ES5's paragraph from Clause 15, starting
>
>     ''The value of the [[Class]] internal property is defined by this
>     specification for every kind of built-in object. The
>     value of the [[Class]] internal property of a host object may be
>     any String value except one of "Arguments",
>
>     "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math",
>     "Number", "Object",
>     "RegExp", and "String".''
>
>     Step 4 uses [[NativeBrand]] in preference to @@toStringTag, which
>     enables the core-language built-ins to return, e.g., "Array"
>     without fear of "~" being prepended.
>
>     This two-level scheme seems like overkill, and the clause 15 intro
>     restriction on host objects claiming, e.g., to be of "Function"
>     [[Class]] (presumably to be updated to [[NativeBrand]]) seems
>     unnecessary to me. If a host function satisfies all the observable
>     requirements of a native one, why not?
>
>
> If a host function satisfies *all* the observable requirements of a 
> native one, then it is simply misclassified. It *is* a host-provided 
> *native* function and should have a [[Class]] of "Function".

[[NativeBrand]] -- but then there's no spoofing issue.

The anti-spoofing defense in ES5 was advisory. Now we have a tiny bit of 
"~"-prefixing mandatory specification, but predicated on (still using 
the old terms) "native" vs. "host" object classes, the [[NativeBrand]] 
test for the former and @@toStringTag for the latter (with "~"-prefixing 
for the 13 names). I think this is the wrong direction.

> (Allen, thank you for getting us away from this awful "host" and 
> "native" terminology!)

Are "ordinary" and "exotic" any better or worse? A rose by any name 
would smell as sweet, a host-rose as sour.

But the @@toStringTag idea is a win. Why not use it uniformly, tag all 
the natives and use advisory language to require that only 
implementation(s) of objects that satisfy, e.g., the function contract, 
can use "Function"?

>     I asked a question aimed more directly at you up-thread: why
>     should *only* the above 12 or 13 names be subject to
>     "~"-prepending when returned from an object that lacks
>     [[NativeBrand]]? Are there not host objects in need of protection
>     from class-spoofing?
>
>
> In the ES5 timeframe, there were hard limits on how much cleanup of 
> host objects we could do before finalizing the spec. Given the 
> constraints, I think it's miraculous that we cleaned them up as much 
> as we did. There is one form of spoofing protection that we did 
> enforce by these rules for host objects, they cannot pretend to be 
> native objects, and no native object can pretend to be a host object.

You guys did make some good moves, but that was then. I would like us to 
go farther, but not in the mandatory-classname-rewriting-list direction.

And I'm really asking whether, should we fail to agree on a less 
mandatory and hacky solution than "~"-prefixing, we will end up needing 
to enlarge the blacklist from 13 names to more. Don't you have to use 
tag-testing on DOM objects in SES?

/be



More information about the es-discuss mailing list