Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
[Merge chakra-core/ChakraCore@cb5557fe2d] [1.6>1.7] [MERGE #3409 @cur…
Browse files Browse the repository at this point in the history
…tisman] 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.
  • Loading branch information
chakrabot authored and kfarnung committed Jul 24, 2017
1 parent 3d768de commit af938b6
Show file tree
Hide file tree
Showing 9 changed files with 1,253 additions and 56 deletions.
4 changes: 2 additions & 2 deletions deps/chakrashim/core/lib/Parser/JsScan.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ function emitToken(token, d, indent) {
r += indent + "p += " + d + ";\r\n";
if (token.res == 1) {
if (token.tk === "tkYIELD") {
r += indent + "if (this->m_fYieldIsKeyword || !this->m_parser || this->m_parser->IsStrictMode()) {" + "\r\n";
r += indent + "if (this->YieldIsKeyword()) {" + "\r\n";
r += indent + " token = " + token.tk + ";\r\n";
r += indent + " goto LReserved;\r\n";
r += indent + "}\r\n";
r += indent + "goto LIdentifier;\r\n";
} else if (token.tk === "tkAWAIT") {
// Note: `await` is only a FutureReservedWord when parsing module scripts (when Module is goal symbol of the grammar)
r += indent + "if (this->m_fAwaitIsKeyword || this->m_fIsModuleCode) {" + "\r\n";
r += indent + "if (this->AwaitIsKeyword()) {" + "\r\n";
r += indent + " token = " + token.tk + ";\r\n";
r += indent + " goto LReserved;\r\n";
r += indent + "}\r\n";
Expand Down
46 changes: 23 additions & 23 deletions deps/chakrashim/core/lib/Parser/Parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ HRESULT Parser::ValidateSyntax(LPCUTF8 pszSrc, size_t encodedCharCount, bool isG

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

uint nestedCount = 0;
Expand Down Expand Up @@ -2929,9 +2929,9 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
isAsyncExpr = true;
}

bool previousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(isAsyncExpr);
bool previousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(isAsyncExpr);
m_pscan->Scan();
m_pscan->SetAwaitIsKeyword(previousAwaitIsKeyword);
m_pscan->SetAwaitIsKeywordRegion(previousAwaitIsKeyword);

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

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

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

if (pnodeFnc && pnodeFnc->sxFnc.IsGenerator())
{
Expand Down Expand Up @@ -5484,8 +5484,8 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
m_grfscr |= uDeferSave;
}

m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);

// Restore the current function.
if (buildAST)
Expand Down Expand Up @@ -6062,9 +6062,9 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u
{
if (!fDeclaration)
{
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(!fDeclaration);
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(!fDeclaration);
m_pscan->Scan();
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
}
else
{
Expand Down Expand Up @@ -6205,8 +6205,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,

if (fLambda)
{
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeyword(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeywordRegion(pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsGenerator());
fPreviousAwaitIsKeyword = m_pscan->SetAwaitIsKeywordRegion(fAsync || (pnodeParentFnc != nullptr && pnodeParentFnc->sxFnc.IsAsync()));
}

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

if (fLambda)
{
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
}

return;
Expand Down Expand Up @@ -6487,8 +6487,8 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,

if (fLambda)
{
m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
}
}

Expand Down Expand Up @@ -6819,9 +6819,9 @@ void Parser::FinishFncNode(ParseNodePtr pnodeFnc)

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

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

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

m_pscan->SetYieldIsKeyword(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeyword(fPreviousAwaitIsKeyword);
m_pscan->SetYieldIsKeywordRegion(fPreviousYieldIsKeyword);
m_pscan->SetAwaitIsKeywordRegion(fPreviousAwaitIsKeyword);
}

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

if (nop == knopYield)
{
if (!m_pscan->YieldIsKeyword() || oplMin > opl)
if (!m_pscan->YieldIsKeywordRegion() || oplMin > opl)
{
// The case where 'yield' is scanned as a keyword (tkYIELD) but the scanner
// is not treating yield as a keyword (!m_pscan->YieldIsKeyword()) occurs
// is not treating yield as a keyword (!m_pscan->YieldIsKeywordRegion()) occurs
// in strict mode non-generator function contexts.
//
// That is, 'yield' is a keyword because of strict mode, but YieldExpression
Expand All @@ -8128,7 +8128,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
}
else if (nop == knopAwait)
{
if (!m_pscan->AwaitIsKeyword() ||
if (!m_pscan->AwaitIsKeywordRegion() ||
m_currentScope->GetScopeType() == ScopeType_Parameter)
{
// As with the 'yield' keyword, the case where 'await' is scanned as a keyword (tkAWAIT)
Expand Down
20 changes: 10 additions & 10 deletions deps/chakrashim/core/lib/Parser/Scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ Scanner<EncodingPolicy>::Scanner(Parser* parser, HashTbl *phtbl, Token *ptoken,

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

m_fYieldIsKeyword = false;
m_fAwaitIsKeyword = false;
m_fYieldIsKeywordRegion = false;
m_fAwaitIsKeywordRegion = false;
}

template <typename EncodingPolicy>
Expand Down Expand Up @@ -475,12 +475,12 @@ tokens Scanner<EncodingPolicy>::ScanIdentifierContinue(bool identifyKwds, bool f
// So we can just assume it is an ID
DebugOnly(int32 cch = UnescapeToTempBuf(pchMin, p));
DebugOnly(tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode()));
Assert(tk == tkID || (tk == tkYIELD && !m_fYieldIsKeyword) || (tk == tkAWAIT && !m_fAwaitIsKeyword));
Assert(tk == tkID || (tk == tkYIELD && !this->YieldIsKeyword()) || (tk == tkAWAIT && !this->AwaitIsKeyword()));
return tkID;
}
int32 cch = UnescapeToTempBuf(pchMin, p);
tokens tk = m_phtbl->TkFromNameLen(m_tempChBuf.m_prgch, cch, IsStrictMode());
return (!m_fYieldIsKeyword && tk == tkYIELD) || (!m_fAwaitIsKeyword && tk == tkAWAIT) ? tkID : tk;
return (!this->YieldIsKeyword() && tk == tkYIELD) || (!this->AwaitIsKeyword() && tk == tkAWAIT) ? tkID : tk;
}

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

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

template <typename EncodingPolicy>
Expand Down
33 changes: 21 additions & 12 deletions deps/chakrashim/core/lib/Parser/Scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,26 +387,35 @@ class Scanner : public IScanner, public EncodingPolicy
ScanState GetScanState() { return m_scanState; }
void SetScanState(ScanState state) { m_scanState = state; }

bool SetYieldIsKeyword(bool fYieldIsKeyword)
bool SetYieldIsKeywordRegion(bool fYieldIsKeywordRegion)
{
bool fPrevYieldIsKeyword = m_fYieldIsKeyword;
m_fYieldIsKeyword = fYieldIsKeyword;
return fPrevYieldIsKeyword;
bool fPrevYieldIsKeywordRegion = m_fYieldIsKeywordRegion;
m_fYieldIsKeywordRegion = fYieldIsKeywordRegion;
return fPrevYieldIsKeywordRegion;
}
bool YieldIsKeywordRegion()
{
return m_fYieldIsKeywordRegion;
}
bool YieldIsKeyword()
{
return m_fYieldIsKeyword;
return YieldIsKeywordRegion() || this->IsStrictMode();
}

bool SetAwaitIsKeyword(bool fAwaitIsKeyword)
bool SetAwaitIsKeywordRegion(bool fAwaitIsKeywordRegion)
{
bool fPrevAwaitIsKeyword = m_fAwaitIsKeyword;
m_fAwaitIsKeyword = fAwaitIsKeyword;
return fPrevAwaitIsKeyword;
bool fPrevAwaitIsKeywordRegion = m_fAwaitIsKeywordRegion;
m_fAwaitIsKeywordRegion = fAwaitIsKeywordRegion;
return fPrevAwaitIsKeywordRegion;
}
bool AwaitIsKeywordRegion()
{
return m_fAwaitIsKeywordRegion;
}

bool AwaitIsKeyword()
{
return m_fAwaitIsKeyword;
return AwaitIsKeywordRegion() || this->m_fIsModuleCode;
}

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

// Temporary buffer.
TemporaryBuffer m_tempChBuf;
Expand Down
4 changes: 2 additions & 2 deletions deps/chakrashim/core/lib/Parser/kwd-swtch.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
case 'w':
if (p[1] == 'a' && p[2] == 'i' && p[3] == 't' && !IsIdContinueNext(p+4, last)) {
p += 4;
if (this->m_fAwaitIsKeyword || this->m_fIsModuleCode) {
if (this->AwaitIsKeyword()) {
token = tkAWAIT;
goto LReserved;
}
Expand Down Expand Up @@ -438,7 +438,7 @@
{
if (p[0] == 'i' && p[1] == 'e' && p[2] == 'l' && p[3] == 'd' && !IsIdContinueNext(p+4, last)) {
p += 4;
if (this->m_fYieldIsKeyword || !this->m_parser || this->m_parser->IsStrictMode()) {
if (this->YieldIsKeyword()) {
token = tkYIELD;
goto LReserved;
}
Expand Down
17 changes: 10 additions & 7 deletions deps/chakrashim/core/test/es6/await-futreserved-only-in-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ function f() {
}
f();

var m = '';
try {
WScript.LoadModule('var await = 0;', 'samethread');
} catch (e) {
m = e.message;
function test(awaitStr)
{
try {
WScript.LoadModule('var ' + awaitStr + ' = 0;', 'samethread');
} catch (e) {
return e.message === 'The use of a keyword for an identifier is invalid';
}
print("Failed: no syntax error of identifier '" + awaitStr + "'");
return false;
}

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

0 comments on commit af938b6

Please sign in to comment.