ES3 10.1.3 says:

"For each FunctionDeclaration in the code, in source text order, create a property of the variable object whose name is the Identifier in the FunctionDeclaration, whose value is the result returned by creating a Function object as described in section 13, and whose attributes are determined by the type of code. If the variable object already has a property with this name, replace its value and attributes. Semantically, this step must follow the creation of FormalParameterList properties."

But in eval code this is a botch, since it requires

function foo(a, s) {
  var x = a * a;
  eval(s);
  return x;
}
alert(foo(2, "function x() { return 'ha ha!'; }"));

to alert the function x's toString results.

Still, the spec is clear enough, and Firefox 3 (not 2 or earlier), Safari, and Opera all agree (I can't test IE atm).

ES3.1 changes the rules to use CreateMutableBinding when entering the eval execution context only if x is not already bound, and in any case then to call SetMutableBinding (10.2.1.2.3 in the feb09 draft). SetMutableBinding calls [[ThrowingPut]]. Strict mode adds value in its own way but let's assume it's not used in the following.

The change in spec between 3 and 3.1 does not affect the outcome for the example above, but changing the attributes of x before the eval call, or giving it a setter somehow (the native implementation might use some kind of internal setter, depending on how it handles eval and function activations), would make a big difference: the old spec says to blow away any pre-existing x including its attributes, getter, and setter.

The new 3.1 language would respect the attributes and call the setter. And 3.1 Object.defineProperty, etc., lets users define setters on objects they can reference.

Since the activation object is censored, the issue becomes function foo in global code, not var or function x in function code. Code on the web today can count on a function declaration being processed from global code (and possibly from eval from global code, depending on the implementation) so that any pre-existing writable binding of the same name is destroyed. This gives some integrity that otherwise can't be recovered.

With ES3.1, programmers will have to use Object.getOwnPropertyDescriptor(this, 'foo') and check first to avoid spoofing and luring attacks via setters. If an unwanted foo pre- exists, the code can work around the name conflict or try to delete that foo.

A pre-existing non-writable (const) property is not a threat (except of the trivial DOS kind), and indeed Firefox throws an error given const foo = 42; (in its own script tag or earlier in the same one as function foo shown above) and then function foo(){...}. Silent failure to update foo would be inferior, but better than recreating foo and violating the integrity of const.

The problem is setters (and getters) on the global object combined with the change to function binding, from re-creation to conditional creation followed by assignment. I can't prove this is going to burn programmers in the future, but I suspect it will. Anway, it is a big enough change from ES3 and implementation behavior -- for global code at least -- that I wanted to bring it up for discussion here.

/be
_______________________________________________
Es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to