Skip to content

Commit cb5557f

Browse files
committed
[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 3631662 + f7ecfb6 commit cb5557f

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())
@@ -4979,9 +4979,9 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49794979

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

4984-
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(fAsync);
4984+
bool fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(fAsync);
49854985

49864986
if (pnodeFnc && pnodeFnc->sxFnc.IsGenerator())
49874987
{
@@ -5484,8 +5484,8 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
54845484
m_grfscr |= uDeferSave;
54855485
}
54865486

5487-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
5488-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
5487+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
5488+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
54895489

54905490
// Restore the current function.
54915491
if (buildAST)
@@ -6062,9 +6062,9 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u
60626062
{
60636063
if (!fDeclaration)
60646064
{
6065-
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(!fDeclaration);
6065+
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(!fDeclaration);
60666066
m_pscan->Scan();
6067-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6067+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
60686068
}
60696069
else
60706070
{
@@ -6205,8 +6205,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
62056205

62066206
if (fLambda)
62076207
{
6208-
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
6209-
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
6208+
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
6209+
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
62106210
}
62116211

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

62376237
if (fLambda)
62386238
{
6239-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6240-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6239+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6240+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
62416241
}
62426242

62436243
return;
@@ -6487,8 +6487,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
64876487

64886488
if (fLambda)
64896489
{
6490-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6491-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6490+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6491+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
64926492
}
64936493
}
64946494

@@ -6819,9 +6819,9 @@ void Parser::FinishFncNode(ParseNodePtr pnodeFnc)
68196819

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

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

68266826
// Skip the arg list.
68276827
m_pscan->ScanNoKeywords();
@@ -6916,8 +6916,8 @@ void Parser::FinishFncNode(ParseNodePtr pnodeFnc)
69166916
Assert(tempNextFunctionId == pnodeFnc->sxFnc.deferredParseNextFunctionId);
69176917
this->m_nextFunctionId = nextFunctionIdSave;
69186918

6919-
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
6920-
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
6919+
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
6920+
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
69216921
}
69226922

69236923
void Parser::FinishFncDecl(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ParseNodePtr *lastNodeRef, bool skipCurlyBraces)
@@ -8108,10 +8108,10 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
81088108

81098109
if (nop == knopYield)
81108110
{
8111-
if (!m_pscan->YieldIsKeyword() || oplMin > opl)
8111+
if (!m_pscan->YieldIsKeywordRegion() || oplMin > opl)
81128112
{
81138113
// The case where 'yield' is scanned as a keyword (tkYIELD) but the scanner
8114-
// is not treating yield as a keyword (!m_pscan->YieldIsKeyword()) occurs
8114+
// is not treating yield as a keyword (!m_pscan->YieldIsKeywordRegion()) occurs
81158115
// in strict mode non-generator function contexts.
81168116
//
81178117
// That is, 'yield' is a keyword because of strict mode, but YieldExpression
@@ -8128,7 +8128,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
81288128
}
81298129
else if (nop == knopAwait)
81308130
{
8131-
if (!m_pscan->AwaitIsKeyword() ||
8131+
if (!m_pscan->AwaitIsKeywordRegion() ||
81328132
m_currentScope->GetScopeType() == ScopeType_Parameter)
81338133
{
81348134
// 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>
@@ -475,12 +475,12 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
475475
// So we can just assume it is an ID
476476
DebugOnly(int32 cch = UnescapeToTempBuf(pchMin, p));
477477
DebugOnly(tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode()));
478-
Assert(tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword));
478+
Assert(tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()));
479479
return tkID;
480480
}
481481
int32 cch = UnescapeToTempBuf(pchMin, p);
482482
tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode());
483-
return (!m_fYieldIsKeyword && tk == tkYIELD) || (!m_fAwaitIsKeyword && tk == tkAWAIT) ? tkID : tk;
483+
return (!this->YieldIsKeyword() && tk == tkYIELD) || (!this->AwaitIsKeyword() && tk == tkAWAIT) ? tkID : tk;
484484
}
485485

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

497497
m_ptoken->SetIdentifier(reinterpret_cast<const char *>(pchMin), (int32)(p - pchMin));
498498
return tkID;
@@ -504,16 +504,16 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
504504
if (!fHasEscape)
505505
{
506506
// If it doesn't have escape, then Scan() should have taken care of keywords (except
507-
// yield if m_fYieldIsKeyword is false, in which case yield is treated as an identifier, and except
508-
// await if m_fAwaitIsKeyword is false, in which case await is treated as an identifier).
507+
// yield if this->YieldIsKeyword() is false, in which case yield is treated as an identifier, and except
508+
// await if this->AwaitIsKeyword() is false, in which case await is treated as an identifier).
509509
// We don't have to check if the name is reserved word and return it as an Identifier
510510
Assert(pid->Tk(IsStrictMode()) == tkID
511-
|| (pid->Tk(IsStrictMode()) == tkYIELD && !m_fYieldIsKeyword)
512-
|| (pid->Tk(IsStrictMode()) == tkAWAIT && !m_fAwaitIsKeyword));
511+
|| (pid->Tk(IsStrictMode()) == tkYIELD && !this->YieldIsKeyword())
512+
|| (pid->Tk(IsStrictMode()) == tkAWAIT && !this->AwaitIsKeyword()));
513513
return tkID;
514514
}
515515
tokens tk = pid->Tk(IsStrictMode());
516-
return tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword) ? tkID : tkNone;
516+
return tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()) ? tkID : tkNone;
517517
}
518518

519519
template <typename EncodingPolicy>

lib/Parser/Scan.h

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

390-
bool SetYieldIsKeyword(bool fYieldIsKeyword)
390+
bool SetYieldIsKeywordRegion(bool fYieldIsKeywordRegion)
391391
{
392-
bool fPrevYieldIsKeyword = m_fYieldIsKeyword;
393-
m_fYieldIsKeyword = fYieldIsKeyword;
394-
return fPrevYieldIsKeyword;
392+
bool fPrevYieldIsKeywordRegion = m_fYieldIsKeywordRegion;
393+
m_fYieldIsKeywordRegion = fYieldIsKeywordRegion;
394+
return fPrevYieldIsKeywordRegion;
395+
}
396+
bool YieldIsKeywordRegion()
397+
{
398+
return m_fYieldIsKeywordRegion;
395399
}
396400
bool YieldIsKeyword()
397401
{
398-
return m_fYieldIsKeyword;
402+
return YieldIsKeywordRegion() || this->IsStrictMode();
399403
}
400404

401-
bool SetAwaitIsKeyword(bool fAwaitIsKeyword)
405+
bool SetAwaitIsKeywordRegion(bool fAwaitIsKeywordRegion)
402406
{
403-
bool fPrevAwaitIsKeyword = m_fAwaitIsKeyword;
404-
m_fAwaitIsKeyword = fAwaitIsKeyword;
405-
return fPrevAwaitIsKeyword;
407+
bool fPrevAwaitIsKeywordRegion = m_fAwaitIsKeywordRegion;
408+
m_fAwaitIsKeywordRegion = fAwaitIsKeywordRegion;
409+
return fPrevAwaitIsKeywordRegion;
406410
}
411+
bool AwaitIsKeywordRegion()
412+
{
413+
return m_fAwaitIsKeywordRegion;
414+
}
415+
407416
bool AwaitIsKeyword()
408417
{
409-
return m_fAwaitIsKeyword;
418+
return AwaitIsKeywordRegion() || this->m_fIsModuleCode;
410419
}
411420

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

689698
// Temporary buffer.
690699
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)