Super use should be recorded in per-function scope
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Nov 2015 21:19:57 +0000 (21:19 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Nov 2015 21:19:57 +0000 (21:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151500

Reviewed by Geoffrey Garen.

"super" use is prohibited under the non-constructor / non-class-method-related functions.
This "super" use should be recorded in per-function scope to check its incorrect use after
parsing a function.
Currently, we accidentally record it to a lexical current scope. So when using "super" inside
a block scope, our "super" use guard miss it.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseMemberExpression):
* parser/Parser.h:
(JSC::Parser::currentVariableScope):
(JSC::Parser::currentFunctionScope):
(JSC::Parser::declareVariable):
* tests/stress/super-in-lexical-scope.js: Added.
(testSyntax):
(testSyntaxError):
(testSyntaxError.test):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/tests/stress/super-in-lexical-scope.js [new file with mode: 0644]

index 92ad000..f91e0f9 100644 (file)
@@ -1,3 +1,27 @@
+2015-11-20  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Super use should be recorded in per-function scope
+        https://bugs.webkit.org/show_bug.cgi?id=151500
+
+        Reviewed by Geoffrey Garen.
+
+        "super" use is prohibited under the non-constructor / non-class-method-related functions.
+        This "super" use should be recorded in per-function scope to check its incorrect use after
+        parsing a function.
+        Currently, we accidentally record it to a lexical current scope. So when using "super" inside
+        a block scope, our "super" use guard miss it.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        * parser/Parser.h:
+        (JSC::Parser::currentVariableScope):
+        (JSC::Parser::currentFunctionScope):
+        (JSC::Parser::declareVariable):
+        * tests/stress/super-in-lexical-scope.js: Added.
+        (testSyntax):
+        (testSyntaxError):
+        (testSyntaxError.test):
+
 2015-11-20  Chris Dumez  <cdumez@apple.com>
 
         Caching of properties on objects that have named property getters is sometimes incorrect
index 4eb855a..6874b27 100644 (file)
@@ -3555,7 +3555,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
         semanticFailIfFalse(currentScope()->isFunction(), "super is only valid inside functions");
         base = context.createSuperExpr(location);
         next();
-        currentScope()->setNeedsSuperBinding();
+        currentFunctionScope()->setNeedsSuperBinding();
     } else if (!baseIsNewTarget)
         base = parsePrimaryExpression(context);
 
@@ -3590,7 +3590,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
                 TreeArguments arguments = parseArguments(context, AllowSpread);
                 failIfFalse(arguments, "Cannot parse call arguments");
                 if (baseIsSuper)
-                    currentScope()->setHasDirectSuper();
+                    currentFunctionScope()->setHasDirectSuper();
                 base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
             }
             m_nonLHSCount = nonLHSCount;
index 6294f31..17b0e81 100644 (file)
@@ -787,6 +787,30 @@ private:
     {
         return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
     }
+
+    ScopeRef currentVariableScope()
+    {
+        unsigned i = m_scopeStack.size() - 1;
+        ASSERT(i < m_scopeStack.size());
+        while (!m_scopeStack[i].allowsVarDeclarations()) {
+            i--;
+            ASSERT(i < m_scopeStack.size());
+        }
+        return ScopeRef(&m_scopeStack, i);
+    }
+
+    ScopeRef currentFunctionScope()
+    {
+        unsigned i = m_scopeStack.size() - 1;
+        ASSERT(i < m_scopeStack.size());
+        while (i && !m_scopeStack[i].isFunctionBoundary()) {
+            i--;
+            ASSERT(i < m_scopeStack.size());
+        }
+        // When reaching the top level scope (it can be non function scope), we return it.
+        return ScopeRef(&m_scopeStack, i);
+    }
+
     
     ScopeRef pushScope()
     {
@@ -833,18 +857,11 @@ private:
     
     DeclarationResultMask declareVariable(const Identifier* ident, DeclarationType type = DeclarationType::VarDeclaration, DeclarationImportType importType = DeclarationImportType::NotImported)
     {
+        if (type == DeclarationType::VarDeclaration)
+            return currentVariableScope()->declareVariable(ident);
+
         unsigned i = m_scopeStack.size() - 1;
         ASSERT(i < m_scopeStack.size());
-
-        if (type == DeclarationType::VarDeclaration) {
-            while (!m_scopeStack[i].allowsVarDeclarations()) {
-                i--;
-                ASSERT(i < m_scopeStack.size());
-            }
-
-            return m_scopeStack[i].declareVariable(ident);
-        }
-
         ASSERT(type == DeclarationType::LetDeclaration || type == DeclarationType::ConstDeclaration);
 
         // Lexical variables declared at a top level scope that shadow arguments or vars are not allowed.
diff --git a/Source/JavaScriptCore/tests/stress/super-in-lexical-scope.js b/Source/JavaScriptCore/tests/stress/super-in-lexical-scope.js
new file mode 100644 (file)
index 0000000..50f388b
--- /dev/null
@@ -0,0 +1,63 @@
+function testSyntax(script) {
+    try {
+        eval(script);
+    } catch (error) {
+        if (error instanceof SyntaxError)
+            throw new Error("Bad error: " + String(error));
+    }
+}
+
+function testSyntaxError(script, message) {
+    var error = null;
+    try {
+        eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("Expected syntax error not thrown");
+
+    if (String(error) !== message)
+        throw new Error("Bad error: " + String(error));
+}
+
+testSyntaxError(`super()`, `SyntaxError: super is only valid inside functions.`);
+testSyntaxError(`super.hello()`, `SyntaxError: super is only valid inside functions.`);
+testSyntaxError(`
+{
+    super();
+}
+`, `SyntaxError: super is only valid inside functions.`);
+testSyntaxError(`
+{
+    super.hello();
+}
+`, `SyntaxError: super is only valid inside functions.`);
+testSyntaxError(`
+function test()
+{
+    super();
+}
+`, `SyntaxError: Cannot call super() outside of a class constructor.`);
+testSyntaxError(`
+function test()
+{
+    super.hello();
+}
+`, `SyntaxError: super can only be used in a method of a derived class.`);
+testSyntaxError(`
+function test()
+{
+    {
+        super();
+    }
+}
+`, `SyntaxError: Cannot call super() outside of a class constructor.`);
+testSyntaxError(`
+function test()
+{
+    {
+        super.hello();
+    }
+}
+`, `SyntaxError: super can only be used in a method of a derived class.`);