Strict mode eval

Andreas Rossberg rossberg at google.com
Thu May 12 02:08:44 PDT 2011


On 11 May 2011 20:30, Mark S. Miller <erights at google.com> wrote:
>
> On Wed, May 11, 2011 at 10:31 AM, Andreas Rossberg <rossberg at google.com>
> wrote:
>>
>> On 11 May 2011 18:31, Mark S. Miller <erights at google.com> wrote:
>> > On Wed, May 11, 2011 at 4:42 AM, Andreas Rossberg <rossberg at google.com>
>> > wrote:
>> >>
>> >> Thanks to everybody for clearing up my confusion. The thing I had
>> >> missed in the spec was Section 10.4.2. And of course, my example was
>> >> too simplistic because it couldn't distinguish caller and global
>> >> context.
>> >>
>> >> At the risk of reviving old discussions, are there any sources
>> >> explaining the rationale behind the current design? The "obvious"
>> >> solution to me would have been having two internal variants/modes of
>> >> (or "entry points" to) the eval function, one strict, one non-strict.
>> >> And depending on the lexical strict mode, the identifier "eval" would
>> >> be bound to the right one.
>> >
>> > I don't think I understand the suggestion. What would the following code
>> > do:
>> >     // non-strict outer context
>> >     function f(eval) {
>> >       var f = eval;
>> >       function g() {
>> >         "use strict";
>> >         eval(str); // [1]
>> >         (1,eval)(str); // [2]
>> >         f(str); // [3]
>> >       }
>> >     }
>> > [1] If the outer eval is bound to the global eval function then this is
>> > a
>> > direct eval, which therefore lexically inherits strictness. So no
>> > problem
>> > here.
>> > [2] The 'eval' identifier is bound in non-strict code and used in strict
>> > code.
>> > [3] Strict code makes no use here of a lexical binding of the identifier
>> > "eval".
>> >
>> > A previous approach which we rejected was to make strictness dynamically
>> > scoped, so all three of the above calls would do strict evals. This was
>> > rejected to avoid the problems of dynamic scoping. Are you suggesting a
>> > rule
>> > that would affect #2 but not #3? If so, IIRC no such rule was previously
>> > proposed.
>>
>> I'm actually suggesting plain lexical scoping. :)
>>
>> Basically, what I'm saying is that the directive "use strict" could
>> simply amount to shadowing the global eval via an implicit "var eval =
>> eval_strict" (unless global eval has already been shadowed lexically).
>> So all uses of the identifier `eval' in that scope would refer to its
>> strict version, no matter when, where, or how you ultimately invoke
>> it. Consequently, all your three examples would behave the same, only
>> depending on the argument to f.
>
> I don't understand. If "use strict" implicitly introduces a "var eval =
> eval_strict;" at the position it occurs, then wouldn't #3 in my example
> still evaluate non-strict?

Assume that

- we distinguish two variants of the eval function, strict and
non-strict -- let's call these values EVAL_s and EVAL_ns.
- initially (in global scope), the identifier `eval' is bound to EVAL_ns.
- in a strict mode scope it will be considered rebound to EVAL_s
instead (unless it has already been shadowed by user code anyway).

(In addition, at least in strict mode, the only calls to `eval' that
are considered _direct_ calls would be those where `eval' statically
refers to the initial binding or one of the implicit strict-mode
rebindings -- i.e., where it has not been shadowed by the user.)

In your example, the `eval' identifier is already shadowed by the
function parameter, so the inner "use strict" would have no effect on
it -- in that scope `eval' is just an ordinary identifier.
Consequently, all 3 examples would behave alike and are non-direct
calls. Whether strict or not solely depends on what you pass in to f:

  // non-strict scope
  f(eval)   // EVAL_ns
  (function() { "use strict"; f(eval) })()  // EVAL_s
  f((function() { "use strict"; return eval })())  // EVAL_s

Does that make sense? The idea is that strict/non-strict is resolved
w.r.t. the static scope where the identifier `eval' occurs. With this
semantics, there would be no way in strict mode to access non-strict
eval, unless it is explicitly provided by someone. With the current
rules that is not the case, because you can easily defeat strict mode
by a random indirection, e.g.:

  "use strict";
  var e = eval
  e("var oops = 666")  // pollutes the global object, although the
whole program is in strict mode

I'm not sure whether that was intentional or not, but it feels strange.

/Andreas


More information about the es-discuss mailing list