JScript eval redux, and some spec diving

JScript eval redux, and some spec diving

  • Comments 4

I was discussing the difference between executing in local and global scopes the other day.  A reader points out something that I forgot to mention – there are two sneaky ways to manipulate the global namespace from an “eval” in Jscript.

  First, the Function constructor constructs a named function in the global scope. This had slipped my mind when I was writing the entry.

  The second trick was very much on my mind but I did not mention as it would be yet another digression.  That is the fact that assigning a value to an undeclared variable creates a new variable in global scope.

  This was on my mind because a couple weeks ago my buddy (and open source zealot, I mean enthusiast) CJ was debugging an irksome incompatibility between Gecko and IE. It turned out to hinge on the fact that in IE, fetching the value of an undefined variable is illegal, but setting it is legal.  According to CJ, in Gecko both are legal.  (I wouldn’t know, never having actually used any browser other than IE since IE3 was in development.)

  Now, if you look at the ECMAScript Revision 3 specification (aka E3) in some depth it becomes clear that IE and Gecko are both in compliance with the spec, and yet incompatible with each other. 

"Howzat?" I hear you ask. The logic is a little tortuous!

  Creating a new global variable when setting an undeclared variable must be legal according to E3 section 10.1.4, line 5, which states that an identifier undeclared in all scopes on the scope chain results in a "null reference", and section 8.7.2, line 6 which states that an assignment to a null reference creates a new variable in the global scope.   IE does this, and I assume that Gecko does as well.

  But setting the value of an undeclared variable must throw an error according to E3 section 8.7.1, line 3, which states that fetching the value of a null reference creates a ReferenceError exception. IE does this. If Gecko creates a variable in some scope rather than throwing a ReferenceError exception then clearly they have produced a situation in which a program running in Gecko has different semantics than when running in the browser used by the other 90% of the world. 

Such situations are, as my buddy CJ discovered, very painful for developers -- mitigating this pain is why my colleagues and I went to the massive trouble and expense of defining the specification in the first place!  However, if that is the case then Gecko is not _actually_ in violation of the specification thanks to E3 section 16, which states:

"An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError)."  [Emphasis added]

  The E3 authors explicitly added the parenthetical clauses to make Gecko-like behaviour legal, though discouraged.  However, the clause is necessary -- without this clause it becomes very difficult to define certain browser-object-model/script-engine interactions in a manner which does not (a) make both IE and Navigator technically noncompliant with the spec, (b) drag lots of extra-language browser semantics into the language specification and (c) make it difficult to extend the language in the future. 

  We earnestly wished to avoid all these situations, so the rule became "any error situation may legally have non-error semantics." This is in marked contrast to, say, the ANSI C specification which rigidly defines what error messages a compliant implementation must produce under various circumstances.

  • Actually, Gecko does raise an error if you try to fetch an undefined variable. Maybe there was some other difference?
  • 1. Mozilla's JS engines (both the C and Java implementations) conform to ECMA-262, all editions, when it comes to throwing ReferenceErrors. Your friend seems to have been misled by something or someone. I welcome a testcase from him that shows foo == 42 or alert(foo) failing to throw a ReferenceError where foo has not been pre-defined, declared, or assigned before that statement is evaluated. 2. You are misreading Chapter 16, although the exception could be worded more carefully. That exception to the rule that an implementation shall report errors as specified allows other predefined (host) properties of the global object than those in the ECMA spec. It is not saying any (e.g., foo) property can be referenced without error. /be
  • Brendan: Well, you'd know better than me, obviously, since you wrote the thing. :-) Ian: As I said, I've never actually tried it -- I'm just reporting on what my friend described. Next time I see him I'll ask for more details.
Page 1 of 1 (3 items)