Skip to content

Commit d2cb4eb

Browse files
committed
[1.7>master] [1.6>1.7] [MERGE #3409 @curtisman] Fix Issue #3376: Escaped yield cannot be an identifier in strict mode
Merge pull request #3409 from curtisman:fix3376 The unescape ID scanning fast path already have the check for strict mode for yield. Refactor the logic and share it with escaped ID scanning code path. Also fixed the escaped await used as ID in module case as well.
2 parents 06a8f89 + cb5557f commit d2cb4eb

File tree

9 files changed

+1253
-56
lines changed

9 files changed

+1253
-56
lines changed

lib/Parser/JsScan.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ function emitToken(token, d, indent) {
1515
r += indent + "p += " + d + ";\r\n";
1616
if (token.res == 1) {
1717
if (token.tk === "tkYIELD") {
18-
r += indent + "if (this->m_fYieldIsKeyword || !this->m_parser || this->m_parser->IsStrictMode()) {" + "\r\n";
18+
r += indent + "if (this->YieldIsKeyword()) {" + "\r\n";
1919
r += indent + " token = " + token.tk + ";\r\n";
2020
r += indent + " goto LReserved;\r\n";
2121
r += indent + "}\r\n";
2222
r += indent + "goto LIdentifier;\r\n";
2323
} else if (token.tk === "tkAWAIT") {
2424
// Note: `await` is only a FutureReservedWord when parsing module scripts (when Module is goal symbol of the grammar)
25-
r += indent + "if (this->m_fAwaitIsKeyword || this->m_fIsModuleCode) {" + "\r\n";
25+
r += indent + "if (this->AwaitIsKeyword()) {" + "\r\n";
2626
r += indent + " token = " + token.tk + ";\r\n";
2727
r += indent + " goto LReserved;\r\n";
2828
r += indent + "}\r\n";

lib/Parser/Parse.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ HRESULT Parser::ValidateSyntax(LPCUTF8 pszSrc, size_t encodedCharCount, bool isG
256256

257257
// Give the scanner the source and get the first token
258258
m_pscan->SetText(pszSrc, 0, encodedCharCount, 0, grfscr);
259-
m_pscan->SetYieldIsKeyword(isGenerator);
260-
m_pscan->SetAwaitIsKeyword(isAsync);
259+
m_pscan->SetYieldIsKeywordRegion(isGenerator);
260+
m_pscan->SetAwaitIsKeywordRegion(isAsync);
261261
m_pscan->Scan();
262262

263263
uint nestedCount = 0;
@@ -2929,9 +2929,9 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
29292929
isAsyncExpr = true;
29302930
}
29312931

2932-
bool previousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(isAsyncExpr);
2932+
bool previousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(isAsyncExpr);
29332933
m_pscan->Scan();
2934-
m_pscan->SetAwaitIsKeyword(previousAwaitIsKeyword);
2934+
m_pscan->SetAwaitIsKeywordRegion(previousAwaitIsKeyword);
29352935

29362936
// We search for an Async expression (a function declaration or an async lambda expression)
29372937
if (isAsyncExpr && !m_pscan->FHadNewLine())
@@ -4983,9 +4983,9 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49834983

49844984
// switch scanner to treat 'yield' as keyword in generator functions
49854985
// or as an identifier in non-generator functions
4986-
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeFnc && pnodeFnc->sxFnc.IsGenerator());
4986+
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(pnodeFnc && pnodeFnc->sxFnc.IsGenerator());
49874987

4988-
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(fAsync);
4988+
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(fAsync);
49894989

49904990
if (pnodeFnc && pnodeFnc->sxFnc.IsGenerator())
49914991
{
@@ -5491,8 +5491,8 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
54915491
m_grfscr |= uDeferSave;
54925492
}
54935493

5494-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
5495-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
5494+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
5495+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
54965496

54975497
// Restore the current function.
54985498
if (buildAST)
@@ -6069,9 +6069,9 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u
60696069
{
60706070
if (!fDeclaration)
60716071
{
6072-
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(!fDeclaration);
6072+
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(!fDeclaration);
60736073
m_pscan->Scan();
6074-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6074+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
60756075
}
60766076
else
60776077
{
@@ -6212,8 +6212,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
62126212

62136213
if (fLambda)
62146214
{
6215-
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
6216-
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
6215+
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
6216+
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
62176217
}
62186218

62196219
Assert(!fNoArg || !fOneArg); // fNoArg and fOneArg can never be true at the same time.
@@ -6243,8 +6243,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
62436243

62446244
if (fLambda)
62456245
{
6246-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6247-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6246+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6247+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
62486248
}
62496249

62506250
return;
@@ -6494,8 +6494,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
64946494

64956495
if (fLambda)
64966496
{
6497-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6498-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6497+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6498+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
64996499
}
65006500
}
65016501

@@ -6826,9 +6826,9 @@ void Parser::FinishFncNode(ParseNodePtr pnodeFnc)
68266826

68276827
// switch scanner to treat 'yield' as keyword in generator functions
68286828
// or as an identifier in non-generator functions
6829-
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeFnc && pnodeFnc->sxFnc.IsGenerator());
6829+
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(pnodeFnc && pnodeFnc->sxFnc.IsGenerator());
68306830

6831-
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(pnodeFnc && pnodeFnc->sxFnc.IsAsync());
6831+
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(pnodeFnc && pnodeFnc->sxFnc.IsAsync());
68326832

68336833
// Skip the arg list.
68346834
m_pscan->ScanNoKeywords();
@@ -6923,8 +6923,8 @@ void Parser::FinishFncNode(ParseNodePtr pnodeFnc)
69236923
Assert(tempNextFunctionId == pnodeFnc->sxFnc.deferredParseNextFunctionId);
69246924
this->m_nextFunctionId = nextFunctionIdSave;
69256925

6926-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6927-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6926+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6927+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
69286928
}
69296929

69306930
void Parser::FinishFncDecl(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ParseNodePtr *lastNodeRef, bool skipCurlyBraces)
@@ -8115,10 +8115,10 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
81158115

81168116
if (nop == knopYield)
81178117
{
8118-
if (!m_pscan->YieldIsKeyword() || oplMin > opl)
8118+
if (!m_pscan->YieldIsKeywordRegion() || oplMin > opl)
81198119
{
81208120
// The case where 'yield' is scanned as a keyword (tkYIELD) but the scanner
8121-
// is not treating yield as a keyword (!m_pscan->YieldIsKeyword()) occurs
8121+
// is not treating yield as a keyword (!m_pscan->YieldIsKeywordRegion()) occurs
81228122
// in strict mode non-generator function contexts.
81238123
//
81248124
// That is, 'yield' is a keyword because of strict mode, but YieldExpression
@@ -8135,7 +8135,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
81358135
}
81368136
else if (nop == knopAwait)
81378137
{
8138-
if (!m_pscan->AwaitIsKeyword() ||
8138+
if (!m_pscan->AwaitIsKeywordRegion() ||
81398139
m_currentScope->GetScopeType() == ScopeType_Parameter)
81408140
{
81418141
// As with the 'yield' keyword, the case where 'await' is scanned as a keyword (tkAWAIT)

lib/Parser/Scan.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ Scanner<EncodingPolicy>::Scanner(Parser* parser, HashTbl *phtbl, Token *ptoken,
104104

105105
this->es6UnicodeMode = scriptContext->GetConfig()->IsES6UnicodeExtensionsEnabled();
106106

107-
m_fYieldIsKeyword = false;
108-
m_fAwaitIsKeyword = false;
107+
m_fYieldIsKeywordRegion = false;
108+
m_fAwaitIsKeywordRegion = false;
109109
}
110110

111111
template <typename EncodingPolicy>
@@ -477,12 +477,12 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
477477
// So we can just assume it is an ID
478478
DebugOnly(int32 cch = UnescapeToTempBuf(pchMin, p));
479479
DebugOnly(tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode()));
480-
Assert(tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword));
480+
Assert(tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()));
481481
return tkID;
482482
}
483483
int32 cch = UnescapeToTempBuf(pchMin, p);
484484
tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode());
485-
return (!m_fYieldIsKeyword && tk == tkYIELD) || (!m_fAwaitIsKeyword && tk == tkAWAIT) ? tkID : tk;
485+
return (!this->YieldIsKeyword() && tk == tkYIELD) || (!this->AwaitIsKeyword() && tk == tkAWAIT) ? tkID : tk;
486486
}
487487

488488
// UTF16 Scanner are only for syntax coloring, so it shouldn't come here.
@@ -494,7 +494,7 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
494494
// So we can just assume it is an ID
495495
DebugOnly(int32 cch = UnescapeToTempBuf(pchMin, p));
496496
DebugOnly(tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode()));
497-
Assert(tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword));
497+
Assert(tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()));
498498

499499
m_ptoken->SetIdentifier(reinterpret_cast<const char *>(pchMin), (int32)(p - pchMin));
500500
return tkID;
@@ -506,16 +506,16 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
506506
if (!fHasEscape)
507507
{
508508
// If it doesn't have escape, then Scan() should have taken care of keywords (except
509-
// yield if m_fYieldIsKeyword is false, in which case yield is treated as an identifier, and except
510-
// await if m_fAwaitIsKeyword is false, in which case await is treated as an identifier).
509+
// yield if this->YieldIsKeyword() is false, in which case yield is treated as an identifier, and except
510+
// await if this->AwaitIsKeyword() is false, in which case await is treated as an identifier).
511511
// We don't have to check if the name is reserved word and return it as an Identifier
512512
Assert(pid->Tk(IsStrictMode()) == tkID
513-
|| (pid->Tk(IsStrictMode()) == tkYIELD && !m_fYieldIsKeyword)
514-
|| (pid->Tk(IsStrictMode()) == tkAWAIT && !m_fAwaitIsKeyword));
513+
|| (pid->Tk(IsStrictMode()) == tkYIELD && !this->YieldIsKeyword())
514+
|| (pid->Tk(IsStrictMode()) == tkAWAIT && !this->AwaitIsKeyword()));
515515
return tkID;
516516
}
517517
tokens tk = pid->Tk(IsStrictMode());
518-
return tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword) ? tkID : tkNone;
518+
return tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()) ? tkID : tkNone;
519519
}
520520

521521
template <typename EncodingPolicy>

lib/Parser/Scan.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -388,26 +388,35 @@ class Scanner : public IScanner, public EncodingPolicy
388388
ScanState GetScanState() { return m_scanState; }
389389
void SetScanState(ScanState state) { m_scanState = state; }
390390

391-
bool SetYieldIsKeyword(bool fYieldIsKeyword)
391+
bool SetYieldIsKeywordRegion(bool fYieldIsKeywordRegion)
392392
{
393-
bool fPrevYieldIsKeyword = m_fYieldIsKeyword;
394-
m_fYieldIsKeyword = fYieldIsKeyword;
395-
return fPrevYieldIsKeyword;
393+
bool fPrevYieldIsKeywordRegion = m_fYieldIsKeywordRegion;
394+
m_fYieldIsKeywordRegion = fYieldIsKeywordRegion;
395+
return fPrevYieldIsKeywordRegion;
396+
}
397+
bool YieldIsKeywordRegion()
398+
{
399+
return m_fYieldIsKeywordRegion;
396400
}
397401
bool YieldIsKeyword()
398402
{
399-
return m_fYieldIsKeyword;
403+
return YieldIsKeywordRegion() || this->IsStrictMode();
400404
}
401405

402-
bool SetAwaitIsKeyword(bool fAwaitIsKeyword)
406+
bool SetAwaitIsKeywordRegion(bool fAwaitIsKeywordRegion)
403407
{
404-
bool fPrevAwaitIsKeyword = m_fAwaitIsKeyword;
405-
m_fAwaitIsKeyword = fAwaitIsKeyword;
406-
return fPrevAwaitIsKeyword;
408+
bool fPrevAwaitIsKeywordRegion = m_fAwaitIsKeywordRegion;
409+
m_fAwaitIsKeywordRegion = fAwaitIsKeywordRegion;
410+
return fPrevAwaitIsKeywordRegion;
407411
}
412+
bool AwaitIsKeywordRegion()
413+
{
414+
return m_fAwaitIsKeywordRegion;
415+
}
416+
408417
bool AwaitIsKeyword()
409418
{
410-
return m_fAwaitIsKeyword;
419+
return AwaitIsKeywordRegion() || this->m_fIsModuleCode;
411420
}
412421

413422
tokens TryRescanRegExp();
@@ -684,8 +693,8 @@ class Scanner : public IScanner, public EncodingPolicy
684693
BYTE m_DeferredParseFlags:2; // suppressStrPid and suppressIdPid
685694
charcount_t m_ichCheck; // character at which completion is to be computed.
686695
bool es6UnicodeMode; // True if ES6Unicode Extensions are enabled.
687-
bool m_fYieldIsKeyword; // Whether to treat 'yield' as an identifier or keyword
688-
bool m_fAwaitIsKeyword; // Whether to treat 'await' as an identifier or keyword
696+
bool m_fYieldIsKeywordRegion; // Whether to treat 'yield' as an identifier or keyword
697+
bool m_fAwaitIsKeywordRegion; // Whether to treat 'await' as an identifier or keyword
689698

690699
// Temporary buffer.
691700
TemporaryBuffer m_tempChBuf;

lib/Parser/kwd-swtch.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
case 'w':
1414
if (p[1] == 'a' && p[2] == 'i' && p[3] == 't' && !IsIdContinueNext(p+4, last)) {
1515
p += 4;
16-
if (this->m_fAwaitIsKeyword || this->m_fIsModuleCode) {
16+
if (this->AwaitIsKeyword()) {
1717
token = tkAWAIT;
1818
goto LReserved;
1919
}
@@ -438,7 +438,7 @@
438438
{
439439
if (p[0] == 'i' && p[1] == 'e' && p[2] == 'l' && p[3] == 'd' && !IsIdContinueNext(p+4, last)) {
440440
p += 4;
441-
if (this->m_fYieldIsKeyword || !this->m_parser || this->m_parser->IsStrictMode()) {
441+
if (this->YieldIsKeyword()) {
442442
token = tkYIELD;
443443
goto LReserved;
444444
}

test/es6/await-futreserved-only-in-modules.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ function f() {
2424
}
2525
f();
2626

27-
var m = '';
28-
try {
29-
WScript.LoadModule('var await = 0;', 'samethread');
30-
} catch (e) {
31-
m = e.message;
27+
function test(awaitStr)
28+
{
29+
try {
30+
WScript.LoadModule('var ' + awaitStr + ' = 0;', 'samethread');
31+
} catch (e) {
32+
return e.message === 'The use of a keyword for an identifier is invalid';
33+
}
34+
print("Failed: no syntax error of identifier '" + awaitStr + "'");
35+
return false;
3236
}
3337

34-
print(m === 'The use of a keyword for an identifier is invalid' ?
35-
'pass' : 'fail');
38+
print(test("await") & test("\\u0061wait")? 'pass' : '');

0 commit comments

Comments
 (0)