[JSC] forbid lexical redeclaration of generator formal parameters
authorcaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Oct 2016 23:20:35 +0000 (23:20 +0000)
committercaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Oct 2016 23:20:35 +0000 (23:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163930

Reviewed by Yusuke Suzuki.

JSTests:

* stress/async-await-syntax.js:
* stress/generator-syntax.js:
(testSyntaxError.gen):
(testSyntaxError.arguments):
(testSyntaxError.eval):
* test262.yaml:

Source/JavaScriptCore:

Also forbids "arguments" and "eval" as generator argument names in strict mode.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::declareRestOrNormalParameter):
* parser/Parser.h:
(JSC::Parser::declareVariable):
(JSC::Parser::hasDeclaredParameter):
(JSC::Parser::isValidStrictMode):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208016 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/async-await-syntax.js
JSTests/stress/generator-syntax.js
JSTests/test262.yaml
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h

index b9050c9..5db8a74 100644 (file)
@@ -1,3 +1,17 @@
+2016-10-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] forbid lexical redeclaration of generator formal parameters
+        https://bugs.webkit.org/show_bug.cgi?id=163930
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/async-await-syntax.js:
+        * stress/generator-syntax.js:
+        (testSyntaxError.gen):
+        (testSyntaxError.arguments):
+        (testSyntaxError.eval):
+        * test262.yaml:
+
 2016-10-26  JF Bastien  <jfbastien@apple.com>
 
         WebAssembly API: implement Instance
index 200d5ea..8853b34 100644 (file)
@@ -355,3 +355,39 @@ function testSyntaxError(script, message) {
         testSyntaxError(`"use strict"; ${nested}`);
     }
 })();
+
+testSyntaxError(`
+async function fn(arguments) {
+    "use strict";
+}
+`, `SyntaxError: Invalid parameters or function name in strict mode.`);
+
+testSyntaxError(`
+async function fn(eval) {
+    "use strict";
+}
+`, `SyntaxError: Invalid parameters or function name in strict mode.`);
+
+testSyntaxError(`
+async function arguments() {
+    "use strict";
+}
+`, `SyntaxError: 'arguments' is not a valid function name in strict mode.`);
+
+testSyntaxError(`
+async function eval() {
+    "use strict";
+}
+`, `SyntaxError: 'eval' is not a valid function name in strict mode.`);
+
+testSyntaxError(`
+async function fn(a) {
+    let a = 1;
+}
+`, `SyntaxError: Cannot declare a let variable twice: 'a'.`);
+
+testSyntaxError(`
+async function fn(b) {
+    const b = 1;
+}
+`, `SyntaxError: Cannot declare a const variable twice: 'b'.`);
index 6f6149b..862c2a5 100644 (file)
@@ -128,3 +128,39 @@ testSyntax(`
 function *gen(g = function *() { yield  }) {
 }
 `);
+
+testSyntaxError(`
+function* gen(arguments) {
+    "use strict";
+}
+`, `SyntaxError: Invalid parameters or function name in strict mode.`);
+
+testSyntaxError(`
+function* gen(eval) {
+    "use strict";
+}
+`, `SyntaxError: Invalid parameters or function name in strict mode.`);
+
+testSyntaxError(`
+function* arguments() {
+    "use strict";
+}
+`, `SyntaxError: 'arguments' is not a valid function name in strict mode.`);
+
+testSyntaxError(`
+function* eval() {
+    "use strict";
+}
+`, `SyntaxError: 'eval' is not a valid function name in strict mode.`);
+
+testSyntaxError(`
+function* gen(a) {
+    let a = 1;
+}
+`, `SyntaxError: Cannot declare a let variable twice: 'a'.`);
+
+testSyntaxError(`
+function* gen(b) {
+    const b = 1;
+}
+`, `SyntaxError: Cannot declare a const variable twice: 'b'.`);
index 9a86193..3e419d9 100644 (file)
 - path: test262/test/language/expressions/object/method-definition/generator-param-init-yield.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/object/method-definition/generator-param-redecl-const.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/object/method-definition/generator-param-redecl-const.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/expressions/object/method-definition/generator-param-redecl-let.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/object/method-definition/generator-param-redecl-let.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/expressions/object/method-definition/generator-params.js
   cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/object/method-definition/generator-params.js
index 7c14df7..69f565b 100644 (file)
@@ -1,3 +1,19 @@
+2016-10-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] forbid lexical redeclaration of generator formal parameters
+        https://bugs.webkit.org/show_bug.cgi?id=163930
+
+        Reviewed by Yusuke Suzuki.
+
+        Also forbids "arguments" and "eval" as generator argument names in strict mode.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::declareRestOrNormalParameter):
+        * parser/Parser.h:
+        (JSC::Parser::declareVariable):
+        (JSC::Parser::hasDeclaredParameter):
+        (JSC::Parser::isValidStrictMode):
+
 2016-10-27  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Include ConsoleAgent in Workers - real console.log support
index 8974adb..d91037c 100644 (file)
@@ -852,7 +852,7 @@ bool Parser<LexerType>::declareRestOrNormalParameter(const Identifier& name, con
         if (m_parserState.lastFunctionName && name == *m_parserState.lastFunctionName)
             semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
         semanticFailureDueToKeyword("parameter name");
-        if (hasDeclaredParameter(name))
+        if (!m_lexer->isReparsingFunction() && hasDeclaredParameter(name))
             semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
         semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
     }
index ad5d36a..15a8f12 100644 (file)
@@ -1165,7 +1165,7 @@ private:
 
         ASSERT(type == DeclarationType::LetDeclaration || type == DeclarationType::ConstDeclaration);
         // Lexical variables declared at a top level scope that shadow arguments or vars are not allowed.
-        if (m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
+        if (!m_lexer->isReparsingFunction() && m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
             return DeclarationResult::InvalidDuplicateDeclaration;
 
         return currentLexicalDeclarationScope()->declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration, importType);
@@ -1222,12 +1222,25 @@ private:
 
     NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident)
     {
+        // FIXME: hasDeclaredParameter() is not valid during reparsing of generator or async function bodies, because their formal
+        // parameters are declared in a scope unavailable during reparsing. Note that it is redundant to call this function during
+        // reparsing anyways, as the function is already guaranteed to be valid by the original parsing.
+        // https://bugs.webkit.org/show_bug.cgi?id=164087
+        ASSERT(!m_lexer->isReparsingFunction());
+
         unsigned i = m_scopeStack.size() - 1;
         ASSERT(i < m_scopeStack.size());
         while (!m_scopeStack[i].allowsVarDeclarations()) {
             i--;
             ASSERT(i < m_scopeStack.size());
         }
+
+        if (m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary()) {
+            // The formal parameters which need to be verified for Generators and Async Function bodies occur
+            // in the outer wrapper function, so pick the outer scope here.
+            i--;
+            ASSERT(i < m_scopeStack.size());
+        }
         return m_scopeStack[i].hasDeclaredParameter(ident);
     }
     
@@ -1382,7 +1395,18 @@ private:
     void endSwitch() { currentScope()->endSwitch(); }
     void setStrictMode() { currentScope()->setStrictMode(); }
     bool strictMode() { return currentScope()->strictMode(); }
-    bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+    bool isValidStrictMode()
+    {
+        int i = m_scopeStack.size() - 1;
+        if (!m_scopeStack[i].isValidStrictMode())
+            return false;
+
+        // In the case of Generator or Async function bodies, also check the wrapper function, whose name or
+        // arguments may be invalid.
+        if (UNLIKELY((m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary()) && i))
+            return m_scopeStack[i - 1].isValidStrictMode();
+        return true;
+    }
     DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
     bool declareRestOrNormalParameter(const Identifier&, const Identifier**);