зеркало из https://github.com/mozilla/gecko-dev.git
ECMA fix to bug (93557). When excecuting the Function constructor,
treat all the 'arguments arguments' as if they were concatenated together as a comma-separated list, and treat the list as if it were the arguments list in a normal function declaration. That is, allow comments, arbitrary whitespace, etc. Fixed by introducing a TokenStream instance in the Function contructor code.
This commit is contained in:
Родитель
48aad57390
Коммит
35af634eff
149
js/ref/jsfun.c
149
js/ref/jsfun.c
|
@ -1306,10 +1306,13 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
const char *filename;
|
||||
JSObject *obj2;
|
||||
JSScopeProperty *sprop;
|
||||
JSString *str;
|
||||
JSString *str, *arg;
|
||||
JSStackFrame *fp;
|
||||
JSTokenStream *ts;
|
||||
JSPrincipals *principals;
|
||||
jschar *collected_args, *cp;
|
||||
size_t args_length;
|
||||
JSTokenType tt;
|
||||
|
||||
if (cx->fp && !cx->fp->constructing) {
|
||||
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
|
||||
|
@ -1346,43 +1349,115 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
if (!fun)
|
||||
return JS_FALSE;
|
||||
|
||||
if ((fp = cx->fp) != NULL && (fp = fp->down) != NULL && fp->script) {
|
||||
filename = fp->script->filename;
|
||||
lineno = js_PCToLineNumber(fp->script, fp->pc);
|
||||
principals = fp->script->principals;
|
||||
} else {
|
||||
filename = NULL;
|
||||
lineno = 0;
|
||||
principals = NULL;
|
||||
}
|
||||
|
||||
n = argc ? argc - 1 : 0;
|
||||
if (n > 0) {
|
||||
/* Collect the function-argument arguments into one string, separated
|
||||
* by commas, then make a tokenstream from that string, and scan it to
|
||||
* get the arguments. We need to throw the full scanner at the
|
||||
* problem, because the argument string can legitimately contain
|
||||
* comments and linefeeds. XXX It might be better to concatenate
|
||||
* everything up into a function definition and pass it to the
|
||||
* compiler, but doing it this way is less of a delta from the old
|
||||
* code. See ECMA 15.3.2.1.
|
||||
*/
|
||||
args_length = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
/* Collect the lengths for all the function-argument arguments. */
|
||||
arg = JSVAL_TO_STRING(argv[i]);
|
||||
args_length += arg->length;
|
||||
}
|
||||
/* Add 1 for each joining comma. */
|
||||
args_length += n - 1;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
atom = js_ValueToStringAtom(cx, argv[i]);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
str = ATOM_TO_STRING(atom);
|
||||
if (!js_IsIdentifier(str)) {
|
||||
JS_ReportError(cx, "illegal formal argument name %s",
|
||||
JS_GetStringBytes(str));
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* Allocate a string to hold the concatenated arguments, including room
|
||||
* for a terminating 0.
|
||||
*/
|
||||
cp = collected_args = (jschar *) JS_malloc(cx, (args_length + 1) *
|
||||
sizeof(jschar));
|
||||
/* Concatenate the arguments into the new string, separated by commas. */
|
||||
for (i = 0; i < n; i++) {
|
||||
arg = JSVAL_TO_STRING(argv[i]);
|
||||
(void)js_strncpy(cp, arg->chars, arg->length);
|
||||
cp += arg->length;
|
||||
/* Add separating comma or terminating 0. */
|
||||
*(cp++) = (i + 1 < n) ? ',' : 0;
|
||||
}
|
||||
|
||||
if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
|
||||
(JSProperty **)&sprop)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* Make a tokenstream that reads from the given string. */
|
||||
ts = js_NewTokenStream(cx, collected_args, args_length, filename, lineno,
|
||||
principals);
|
||||
if (!ts) {
|
||||
JS_free(cx, collected_args);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
tt = js_GetToken(cx, ts);
|
||||
/* The argument string may be empty or contain no tokens. */
|
||||
if (tt != TOK_EOF) {
|
||||
while (1) {
|
||||
/* Check that it's a name. This also implicitly guards against
|
||||
* TOK_ERROR.
|
||||
*/
|
||||
if (tt != TOK_NAME) {
|
||||
JS_ReportError(cx, "missing formal parameter");
|
||||
goto badargs;
|
||||
}
|
||||
/* Get the atom corresponding to the name from the tokenstream;
|
||||
* we're assured at this point that it's a valid identifier.
|
||||
*/
|
||||
atom = ts->token.t_atom;
|
||||
if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
|
||||
(JSProperty **)&sprop)) {
|
||||
goto badargs;
|
||||
}
|
||||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
if (sprop && obj2 == obj) {
|
||||
PR_ASSERT(sprop->getter == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportError(cx, "duplicate formal argument %s",
|
||||
ATOM_BYTES(atom));
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (sprop && obj2 == obj) {
|
||||
PR_ASSERT(sprop->getter == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportError(cx, "duplicate formal argument %s",
|
||||
ATOM_BYTES(atom));
|
||||
goto badargs;
|
||||
}
|
||||
#endif
|
||||
if (sprop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
if (!js_DefineProperty(cx, obj, (jsid)atom, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
PR_ASSERT(sprop);
|
||||
sprop->id = INT_TO_JSVAL(fun->nargs++);
|
||||
OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
|
||||
if (sprop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
if (!js_DefineProperty(cx, obj, (jsid)atom, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop)) {
|
||||
goto badargs;
|
||||
}
|
||||
PR_ASSERT(sprop);
|
||||
sprop->id = INT_TO_JSVAL(fun->nargs++);
|
||||
OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
|
||||
|
||||
/* Done with the NAME; get the next token. */
|
||||
tt = js_GetToken(cx, ts);
|
||||
/* Stop if we've reached the end of the string. */
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
|
||||
/* If a comma is seen, get the next token. Otherwise, let the
|
||||
* loop catch the error.
|
||||
*/
|
||||
if (tt == TOK_COMMA)
|
||||
tt = js_GetToken(cx, ts);
|
||||
}
|
||||
}
|
||||
/* Clean up. */
|
||||
JS_free(cx, collected_args);
|
||||
if (!js_CloseTokenStream(cx, ts))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
|
@ -1413,6 +1488,14 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
return JS_FALSE;
|
||||
return js_ParseFunctionBody(cx, ts, fun) &&
|
||||
js_CloseTokenStream(cx, ts);
|
||||
|
||||
badargs:
|
||||
/* Clean up the arguments string and tokenstream if we failed to parse
|
||||
* the arguments.
|
||||
*/
|
||||
JS_free(cx, collected_args);
|
||||
(void)js_CloseTokenStream(cx, ts);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
|
149
js/src/jsfun.c
149
js/src/jsfun.c
|
@ -1305,10 +1305,13 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
const char *filename;
|
||||
JSObject *obj2;
|
||||
JSScopeProperty *sprop;
|
||||
JSString *str;
|
||||
JSString *str, *arg;
|
||||
JSStackFrame *fp;
|
||||
JSTokenStream *ts;
|
||||
JSPrincipals *principals;
|
||||
jschar *collected_args, *cp;
|
||||
size_t args_length;
|
||||
JSTokenType tt;
|
||||
|
||||
if (cx->fp && !cx->fp->constructing) {
|
||||
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
|
||||
|
@ -1345,43 +1348,115 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
if (!fun)
|
||||
return JS_FALSE;
|
||||
|
||||
if ((fp = cx->fp) != NULL && (fp = fp->down) != NULL && fp->script) {
|
||||
filename = fp->script->filename;
|
||||
lineno = js_PCToLineNumber(fp->script, fp->pc);
|
||||
principals = fp->script->principals;
|
||||
} else {
|
||||
filename = NULL;
|
||||
lineno = 0;
|
||||
principals = NULL;
|
||||
}
|
||||
|
||||
n = argc ? argc - 1 : 0;
|
||||
if (n > 0) {
|
||||
/* Collect the function-argument arguments into one string, separated
|
||||
* by commas, then make a tokenstream from that string, and scan it to
|
||||
* get the arguments. We need to throw the full scanner at the
|
||||
* problem, because the argument string can legitimately contain
|
||||
* comments and linefeeds. XXX It might be better to concatenate
|
||||
* everything up into a function definition and pass it to the
|
||||
* compiler, but doing it this way is less of a delta from the old
|
||||
* code. See ECMA 15.3.2.1.
|
||||
*/
|
||||
args_length = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
/* Collect the lengths for all the function-argument arguments. */
|
||||
arg = JSVAL_TO_STRING(argv[i]);
|
||||
args_length += arg->length;
|
||||
}
|
||||
/* Add 1 for each joining comma. */
|
||||
args_length += n - 1;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
atom = js_ValueToStringAtom(cx, argv[i]);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
str = ATOM_TO_STRING(atom);
|
||||
if (!js_IsIdentifier(str)) {
|
||||
JS_ReportError(cx, "illegal formal argument name %s",
|
||||
JS_GetStringBytes(str));
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* Allocate a string to hold the concatenated arguments, including room
|
||||
* for a terminating 0.
|
||||
*/
|
||||
cp = collected_args = (jschar *) JS_malloc(cx, (args_length + 1) *
|
||||
sizeof(jschar));
|
||||
/* Concatenate the arguments into the new string, separated by commas. */
|
||||
for (i = 0; i < n; i++) {
|
||||
arg = JSVAL_TO_STRING(argv[i]);
|
||||
(void)js_strncpy(cp, arg->chars, arg->length);
|
||||
cp += arg->length;
|
||||
/* Add separating comma or terminating 0. */
|
||||
*(cp++) = (i + 1 < n) ? ',' : 0;
|
||||
}
|
||||
|
||||
if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
|
||||
(JSProperty **)&sprop)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* Make a tokenstream that reads from the given string. */
|
||||
ts = js_NewTokenStream(cx, collected_args, args_length, filename, lineno,
|
||||
principals);
|
||||
if (!ts) {
|
||||
JS_free(cx, collected_args);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
tt = js_GetToken(cx, ts);
|
||||
/* The argument string may be empty or contain no tokens. */
|
||||
if (tt != TOK_EOF) {
|
||||
while (1) {
|
||||
/* Check that it's a name. This also implicitly guards against
|
||||
* TOK_ERROR.
|
||||
*/
|
||||
if (tt != TOK_NAME) {
|
||||
JS_ReportError(cx, "missing formal parameter");
|
||||
goto badargs;
|
||||
}
|
||||
/* Get the atom corresponding to the name from the tokenstream;
|
||||
* we're assured at this point that it's a valid identifier.
|
||||
*/
|
||||
atom = ts->token.t_atom;
|
||||
if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
|
||||
(JSProperty **)&sprop)) {
|
||||
goto badargs;
|
||||
}
|
||||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
if (sprop && obj2 == obj) {
|
||||
PR_ASSERT(sprop->getter == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportError(cx, "duplicate formal argument %s",
|
||||
ATOM_BYTES(atom));
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (sprop && obj2 == obj) {
|
||||
PR_ASSERT(sprop->getter == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportError(cx, "duplicate formal argument %s",
|
||||
ATOM_BYTES(atom));
|
||||
goto badargs;
|
||||
}
|
||||
#endif
|
||||
if (sprop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
if (!js_DefineProperty(cx, obj, (jsid)atom, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
PR_ASSERT(sprop);
|
||||
sprop->id = INT_TO_JSVAL(fun->nargs++);
|
||||
OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
|
||||
if (sprop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
if (!js_DefineProperty(cx, obj, (jsid)atom, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop)) {
|
||||
goto badargs;
|
||||
}
|
||||
PR_ASSERT(sprop);
|
||||
sprop->id = INT_TO_JSVAL(fun->nargs++);
|
||||
OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
|
||||
|
||||
/* Done with the NAME; get the next token. */
|
||||
tt = js_GetToken(cx, ts);
|
||||
/* Stop if we've reached the end of the string. */
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
|
||||
/* If a comma is seen, get the next token. Otherwise, let the
|
||||
* loop catch the error.
|
||||
*/
|
||||
if (tt == TOK_COMMA)
|
||||
tt = js_GetToken(cx, ts);
|
||||
}
|
||||
}
|
||||
/* Clean up. */
|
||||
JS_free(cx, collected_args);
|
||||
if (!js_CloseTokenStream(cx, ts))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
|
@ -1412,6 +1487,14 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
return JS_FALSE;
|
||||
return js_ParseFunctionBody(cx, ts, fun) &&
|
||||
js_CloseTokenStream(cx, ts);
|
||||
|
||||
badargs:
|
||||
/* Clean up the arguments string and tokenstream if we failed to parse
|
||||
* the arguments.
|
||||
*/
|
||||
JS_free(cx, collected_args);
|
||||
(void)js_CloseTokenStream(cx, ts);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
|
Загрузка…
Ссылка в новой задаче