mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 610350 - Assigning to a named function's name in strict mode code should throw. r=brendan
This commit is contained in:
parent
fa572289d5
commit
c137b2d4d9
@ -2500,15 +2500,28 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
|
||||
|
||||
/*
|
||||
* Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we
|
||||
* cannot be sure cg->fun() is not something of the form:
|
||||
* Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
|
||||
* address two cases: a new binding introduced by eval, and
|
||||
* assignment to the name in strict mode.
|
||||
*
|
||||
* var ff = (function f(s) { eval(s); return f; });
|
||||
* var fun = (function f(s) { eval(s); return f; });
|
||||
* assertEq(fun("var f = 42"), 42);
|
||||
*
|
||||
* where a caller invokes ff("var f = 42"). The result returned for
|
||||
* such an invocation must be 42, since the callee name is
|
||||
* lexically bound in an outer declarative environment from the
|
||||
* function's activation. See jsfun.cpp:call_resolve.
|
||||
* ECMAScript specifies that a function expression's name is bound
|
||||
* in a lexical environment distinct from that used to bind its
|
||||
* named parameters, the arguments object, and its variables. The
|
||||
* new binding for "var f = 42" shadows the binding for the
|
||||
* function itself, so the name of the function will not refer to
|
||||
* the function.
|
||||
*
|
||||
* (function f() { "use strict"; f = 12; })();
|
||||
*
|
||||
* Outside strict mode, assignment to a function expression's name
|
||||
* has no effect. But in strict mode, this attempt to mutate an
|
||||
* immutable binding must throw a TypeError. We implement this by
|
||||
* not optimizing such assignments and by marking such functions as
|
||||
* heavyweight, ensuring that the function name is represented in
|
||||
* the scope chain so that assignment will throw a TypeError.
|
||||
*/
|
||||
JS_ASSERT(op != JSOP_DELNAME);
|
||||
if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
|
||||
|
@ -3843,9 +3843,20 @@ NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_
|
||||
|
||||
pn->pn_dflags |= dflag;
|
||||
|
||||
/*
|
||||
* Both arguments and the enclosing function's name are immutable bindings
|
||||
* in ES5, so assignments to them must do nothing or throw a TypeError
|
||||
* depending on code strictness. Assignment to arguments is a syntax error
|
||||
* in strict mode and thus cannot happen. Outside strict mode, we optimize
|
||||
* away assignment to the function name. For assignment to function name
|
||||
* to fail in strict mode, we must have a binding for it in the scope
|
||||
* chain; we ensure this happens by making such functions heavyweight.
|
||||
*/
|
||||
JSAtom *lname = pn->pn_atom;
|
||||
if (lname == cx->runtime->atomState.argumentsAtom)
|
||||
if (lname == cx->runtime->atomState.argumentsAtom ||
|
||||
(tc->inFunction() && lname == tc->fun()->atom)) {
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
|
42
js/src/tests/ecma_5/strict/assign-to-callee-name.js
Normal file
42
js/src/tests/ecma_5/strict/assign-to-callee-name.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'assign-to-callee-name.js';
|
||||
var BUGNUMBER = 610350;
|
||||
var summary =
|
||||
"Assigning to a function expression's name within that function should " +
|
||||
"throw a TypeError in strict mode code";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var f = function assignSelfStrict() { "use strict"; assignSelfStrict = 12; };
|
||||
|
||||
try
|
||||
{
|
||||
var r = f();
|
||||
throw new Error("should have thrown a TypeError, returned " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"didn't throw a TypeError: " + e);
|
||||
}
|
||||
|
||||
var assignSelf = 42;
|
||||
var f2 = function assignSelf() { assignSelf = 12; };
|
||||
|
||||
f2(); // shouldn't throw, does nothing
|
||||
assertEq(assignSelf, 42);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
@ -37,4 +37,5 @@ script regress-532254.js
|
||||
script regress-532041.js
|
||||
script unbrand-this.js
|
||||
script this-for-function-expression-recursion.js
|
||||
script assign-to-callee-name.js
|
||||
script directive-prologue-01.js
|
||||
|
Loading…
Reference in New Issue
Block a user