Coercing 'this' (was: Topic list - pending changes and issues for the ES3.1 spec)

David-Sarah Hopwood david.hopwood at industrial-designers.co.uk
Mon Sep 15 19:28:23 PDT 2008


Mark S. Miller wrote:
> On Thu, Sep 11, 2008 at 11:11 AM, Brendan Eich <brendan at mozilla.org> wrote:
> 
>> The ES3 spec language uses null as the implicit 'this' value
>> associated with calling a function as a function. However, since the
>> current spec language also coerces both null and undefined to the
>> global object, it is unobservable whether null or undefined is used as
>> the implicit 'this' value. In ES3.1 strict this difference becomes
>> observable. In the interests of explaining 'this'-binding as being
>> more like parameter-binding, I would like to see this changed to
>> undefined. Calling a function as a function is like calling it without
>> an argument for its 'this' parameter. I think this is more intuitive.
>>
>> This is strictly more useful than the current mess, and David-Sarah made
>> good use of it in his Date self-hosting for the Date constructor function,
>> so it can tell when it's called as a function. But it's still not enough in
>> general:
>>
>> var funnyObj = {method: Date}
>> funnyObj.method(2008,9,11)
>>
>> would bind funnyObj to |this| in Date, which would flow into the
>> constructor-case code as the new Date object to initialize.

This turns out to be a potential security bug in Jacaranda draft-0.3
(<http://www.jacaranda.org/jacaranda-spec-0.3.txt>).

Normally functions that refer directly to 'this' are not first-class in
Jacaranda. The bug is that Array, Boolean, Date, Number, RegExp, String,
and *Error are functions that refer to 'this', and they are first-class
expressions.

In general a constructor can either return a new constructed object,
or initialize the 'this' object "in-place". I've only done limited
testing, but it appears that the implementations of the global
constructors in Firefox 3 and IE7 return new constructed objects,
which means that the bug would not have been exploitable in those
browsers. In any case, I will close off this line of attack in
Jacaranda draft-0.4.

The fix is easy -- make references to these constructors second-class
expressions. For those who have read the Jacaranda spec and are
interested in the detail: change the definition of expClass in the
<id::unreservedIdentifier> case of <PrimaryExpression> from

       expClass = (id is <exposedConstant>) ? 0 :
                    (id.text == 'arguments') ? 4 : 1 }

to

       expClass = (id is <exposedConstant>) ? 0 :
                    (id is <secondClassConstructor>) ? 2 :
                      (id.text == 'arguments') ? 4 : 1 }

and add the following production:

  <secondClassConstructor> : one of
    Array Boolean Date Number RegExp String Error EvalError SyntaxError
    TypeError RangeError ReferenceError URIError

(No other constructors that refer to 'this' are directly accessible in
Jacaranda.)

> Agreed that this proposal does not prevent this existing confusion. Neither
> does it make it worse. If there's something we can plausibly do to fix this,
> I'd love to! Any suggestions?

The problem here is the lack of any run-time type distinction between
constructors and other functions. I don't see how to fix the existing
confusion in a compatible way. However, when we add the class feature in
ES-Harmony, we should avoid making it worse by using a desugaring that
allows the class name to be used with 'new', but prevents any use as a
function from breaking object encapsulation.

[...]
> If "strict" suppresses non-stratified reflection that prevents many useful
> optimizations (with, delete <var>, arguments.caller, Function.caller,
> Function.arguments) and removes pointless and costly wrapping, then the
> common wisdom may become "Make your program work under strict mode so it'll
> be faster."

That would certainly be nice.

-- 
David-Sarah Hopwood


More information about the Es-discuss mailing list