Bug 601262 - A string literal containing an octal escape before a strict mode directive should be a syntax error. (Yes, this requirement is ugly, but it's what ES5 says.) r=brendan

--HG--
extra : rebase_source : c30be5f90e4b069da4ea6f035598f9a3262fa8e0
This commit is contained in:
Jeff Walden 2010-10-13 04:00:28 -07:00
parent bf3493284e
commit 5997a2fb7a
6 changed files with 115 additions and 9 deletions

View File

@ -865,6 +865,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
#endif
inDirectivePrologue = true;
tokenStream.setOctalCharacterEscape(false);
for (;;) {
tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF) {
@ -879,8 +880,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
goto out;
JS_ASSERT(!cg.blockNode);
if (inDirectivePrologue)
inDirectivePrologue = parser.recognizeDirectivePrologue(pn);
if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
goto out;
if (!js_FoldConstants(cx, pn, &cg))
goto out;
@ -3225,13 +3226,33 @@ Parser::functionExpr()
* if it can't possibly be a directive, now or in the future.
*/
bool
Parser::recognizeDirectivePrologue(JSParseNode *pn)
Parser::recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember)
{
if (!pn->isDirectivePrologueMember())
return false;
*isDirectivePrologueMember = pn->isDirectivePrologueMember();
if (!*isDirectivePrologueMember)
return true;
if (pn->isDirective()) {
JSAtom *directive = pn->pn_kid->pn_atom;
if (directive == context->runtime->atomState.useStrictAtom) {
/*
* Unfortunately, Directive Prologue members in general may contain
* escapes, even while "use strict" directives may not. Therefore
* we must check whether an octal character escape has been seen in
* any previous directives whenever we encounter a "use strict"
* directive, so that the octal escape is properly treated as a
* syntax error. An example of this case:
*
* function error()
* {
* "\145"; // octal escape
* "use strict"; // retroactively makes "\145" a syntax error
* }
*/
if (tokenStream.hasOctalCharacterEscape()) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DEPRECATED_OCTAL);
return false;
}
tc->flags |= TCF_STRICT_MODE_CODE;
tokenStream.setStrictMode();
}
@ -3249,7 +3270,6 @@ Parser::statements()
{
JSParseNode *pn, *pn2, *saveBlock;
TokenKind tt;
bool inDirectivePrologue = tc->atTopLevel();
JS_CHECK_RECURSION(context, return NULL);
@ -3262,6 +3282,8 @@ Parser::statements()
saveBlock = tc->blockNode;
tc->blockNode = pn;
bool inDirectivePrologue = tc->atTopLevel();
tokenStream.setOctalCharacterEscape(false);
for (;;) {
tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF || tt == TOK_RC) {
@ -3279,8 +3301,8 @@ Parser::statements()
return NULL;
}
if (inDirectivePrologue)
inDirectivePrologue = recognizeDirectivePrologue(pn2);
if (inDirectivePrologue && !recognizeDirectivePrologue(pn2, &inDirectivePrologue))
return NULL;
if (pn2->pn_type == TOK_FUNCTION) {
/*

View File

@ -1118,7 +1118,7 @@ private:
/*
* Additional JS parsers.
*/
bool recognizeDirectivePrologue(JSParseNode *pn);
bool recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember);
enum FunctionType { GETTER, SETTER, GENERAL };
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,

View File

@ -1192,6 +1192,7 @@ TokenStream::getTokenInternal()
JSMSG_DEPRECATED_OCTAL)) {
goto error;
}
setOctalCharacterEscape();
}
if ('0' <= c && c < '8') {
val = 8 * val + JS7_UNDEC(c);

View File

@ -263,6 +263,7 @@ enum TokenStreamFlags
TSF_XMLTAGMODE = 0x200, /* scanning within an XML tag in E4X */
TSF_XMLTEXTMODE = 0x400, /* scanning XMLText terminal from E4X */
TSF_XMLONLYMODE = 0x800, /* don't scan {expr} within text/tag */
TSF_OCTAL_CHAR = 0x1000, /* observed a octal character escape */
/*
* To handle the hard case of contiguous HTML comments, we want to clear the
@ -333,12 +334,15 @@ class TokenStream
void setXMLTagMode(bool enabled = true) { setFlag(enabled, TSF_XMLTAGMODE); }
void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); }
void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); }
void setOctalCharacterEscape(bool enabled = true) { setFlag(enabled, TSF_OCTAL_CHAR); }
bool isStrictMode() { return !!(flags & TSF_STRICT_MODE_CODE); }
bool isXMLTagMode() { return !!(flags & TSF_XMLTAGMODE); }
bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); }
bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); }
bool isEOF() const { return !!(flags & TSF_EOF); }
bool isError() const { return !!(flags & TSF_ERROR); }
bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
/* Mutators. */
bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap);

View File

@ -0,0 +1,78 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
//-----------------------------------------------------------------------------
var BUGNUMBER = 601262;
var summary =
"A string literal containing an octal escape before a strict mode " +
"directive should be a syntax error";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
try
{
eval(" '\\145'; 'use strict'; ");
throw new Error("no error thrown for eval");
}
catch (e)
{
assertEq(e instanceof SyntaxError, true,
"wrong error for octal-escape before strict directive in eval");
}
try
{
Function(" '\\145'; 'use strict'; ");
throw new Error("no error thrown for Function");
}
catch (e)
{
assertEq(e instanceof SyntaxError, true,
"wrong error for octal-escape before strict directive in Function");
}
try
{
eval(" function f(){ '\\145'; 'use strict'; } ");
throw new Error("no error thrown for eval of function");
}
catch (e)
{
assertEq(e instanceof SyntaxError, true,
"wrong error for octal-escape before strict directive in eval of " +
"function");
}
try
{
Function(" function f(){ '\\145'; 'use strict'; } ");
throw new Error("no error thrown for eval of function");
}
catch (e)
{
assertEq(e instanceof SyntaxError, true,
"wrong error for octal-escape before strict directive in eval of " +
"function");
}
eval("function notAnError1() { 5; '\\145'; function g() { 'use strict'; } }");
Function("function notAnError2() { 5; '\\145'; function g() { 'use strict'; } }");
function notAnError3()
{
5;
"\145";
function g() { "use strict"; }
}
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");

View File

@ -37,3 +37,4 @@ script regress-532254.js
script regress-532041.js
script unbrand-this.js
script this-for-function-expression-recursion.js
script directive-prologue-01.js