Lexical scoping of 'function' in sloppy mode breaks legal ES5

Andreas Rossberg rossberg at google.com
Mon Aug 19 10:20:46 PDT 2013


On 19 August 2013 19:02, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
>
> On Aug 19, 2013, at 8:38 AM, Andreas Rossberg wrote:
>
>> While debugging a V8 issue I just realised another incompatibility
>> with introducing lexical function declarations in sloppy mode that I
>> think we haven't observed yet. Consider the following code:
>>
>> function f() {
>>  var x = 0
>>  try {
>>    throw 1
>>  } catch (x) {
>>    eval("function g() { return x }")
>>  }
>>  return g()
>> }
>>
>> This function is legal, and supposed to return 1 according to my
>> reading of the ES5 spec.
>
> I don't think so.  according to ES5 10.4.2 The VariableEnvironment of the eval'ed code should be set to the VariableEnvironment of the calling context.  That variable environment is the outer cope of function f that has 0 as the value of its x binding. When g is instantiated that variable environment will be its [[Scope]] so "return x" should return 0.

You are right, although the discrepancy between FunctionExpression and
FunctionDeclaration feels really odd -- I wonder how that came about.
It also means that both Firefox and Safari handle the example
incorrectly (though at least they don't crash :) ).


>> But lexically scoped function declarations
>> should make it throw a ReferenceError instead.
>
> But, regardless of what g returns, I agree that the ES5 spec. says that the above code produces a binding for g in f's outer scope.
>
>>
>> Unlike the other legacy issues with sloppy-mode lexical function
>> scoping that we have discussed before this one is actually covered by
>> the current spec.
>
> It seems like this could be specified  such that sloppy direct eval instantiates such functions using exactly the ES5 scoping rules.  However, I suspect that is likely to cause even more confusion in the future.

I agree, that sounds like a rather unattractive solution.


>> Is such a breaking change an issue? V8 currently
>> crashes on the above code, so this particular example probably is not
>> a real-world problem. 8) However, there are simpler examples, e.g.:
>>
>> function f() {
>>  if (true) { eval("function g() { return 1 }") }
>>  return g()
>> }
>>
>> Do we know if this is something that occurs in practice?
>
> Does V8 crash on the simpler example?  Does it produce a ReferenceError (not conforming to ES5)  on the call to g()? You're implementation may be the best test of what occurs in practice.

V8 works fine on the simpler example, and it seems that FF and Safari
do, too. So such code could be out in the wild.

/Andreas


More information about the es-discuss mailing list