Assertion failure for super() call in direct eval in method function
https://bugs.webkit.org/show_bug.cgi?id=157091
Reviewed by Darin Adler.
While we ensure that direct super is under the correct context,
we don't check it for the eval code. This patch moves the check from the end of parsing the function
to the places where we found the direct super or the super bindings. This covers the direct eval that
contains the direct super calls.
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseMemberExpression):
* parser/Parser.h:
(JSC::Scope::hasDirectSuper):
(JSC::Scope::setHasDirectSuper):
(JSC::Scope::needsSuperBinding):
(JSC::Scope::setNeedsSuperBinding):
(JSC::Parser::closestParentOrdinaryFunctionNonLexicalScope):
* tests/stress/eval-and-super.js: Added.
(shouldBe):
(shouldThrow):
(prototype.m):
(prototype.n):
* tests/stress/generator-and-super.js: Added.
(testSyntaxError):
(testSyntaxError.Base.prototype.hello):
(testSyntaxError.Base.prototype.ok):
(testSyntaxError.Base):
(Hello.prototype.gen):
(Hello):
(testSyntaxError.hello):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@200409 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index d3121a3..a97f552 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,39 @@
+2016-05-04 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ Assertion failure for super() call in direct eval in method function
+ https://bugs.webkit.org/show_bug.cgi?id=157091
+
+ Reviewed by Darin Adler.
+
+ While we ensure that direct super is under the correct context,
+ we don't check it for the eval code. This patch moves the check from the end of parsing the function
+ to the places where we found the direct super or the super bindings. This covers the direct eval that
+ contains the direct super calls.
+
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
+ (JSC::Parser<LexerType>::parseFunctionInfo):
+ (JSC::Parser<LexerType>::parseMemberExpression):
+ * parser/Parser.h:
+ (JSC::Scope::hasDirectSuper):
+ (JSC::Scope::setHasDirectSuper):
+ (JSC::Scope::needsSuperBinding):
+ (JSC::Scope::setNeedsSuperBinding):
+ (JSC::Parser::closestParentOrdinaryFunctionNonLexicalScope):
+ * tests/stress/eval-and-super.js: Added.
+ (shouldBe):
+ (shouldThrow):
+ (prototype.m):
+ (prototype.n):
+ * tests/stress/generator-and-super.js: Added.
+ (testSyntaxError):
+ (testSyntaxError.Base.prototype.hello):
+ (testSyntaxError.Base.prototype.ok):
+ (testSyntaxError.Base):
+ (Hello.prototype.gen):
+ (Hello):
+ (testSyntaxError.hello):
+
2016-05-03 Filip Pizlo <fpizlo@apple.com>
REGRESSION(r200383): Setting lazily initialized properties across frame boundaries crashes
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 3bcd3eb..f182a20 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -505,6 +505,9 @@
{
AutoPopScopeRef generatorBodyScope(this, pushScope());
generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+ generatorBodyScope->setConstructorKind(ConstructorKind::None);
+ generatorBodyScope->setExpectedSuperBinding(m_superBinding);
+
SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
@@ -2115,16 +2118,15 @@
if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
AutoPopScopeRef generatorBodyScope(this, pushScope());
generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+ generatorBodyScope->setConstructorKind(ConstructorKind::None);
+ generatorBodyScope->setExpectedSuperBinding(expectedSuperBinding);
+
functionInfo.body = performParsingFunctionBody();
// When a generator has a "use strict" directive, a generator function wrapping it should be strict mode.
if (generatorBodyScope->strictMode())
functionScope->setStrictMode();
- semanticFailIfTrue(generatorBodyScope->hasDirectSuper(), "super is not valid in this context");
- if (generatorBodyScope->needsSuperBinding())
- semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
-
popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
} else
functionInfo.body = performParsingFunctionBody();
@@ -2137,26 +2139,6 @@
semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
}
- // It unncecessary to check of using super during reparsing one more time. Also it can lead to syntax error
- // in case of arrow function becuase during reparsing we don't know that parse arrow function
- // inside of the constructor or method
- if (!m_lexer->isReparsingFunction()) {
- if (functionScope->hasDirectSuper()) {
- ScopeRef scopeRef = closestParentOrdinaryFunctionNonLexicalScope();
- ConstructorKind functionConstructorKind = functionBodyType == StandardFunctionBodyBlock && !scopeRef->isEvalContext()
- ? constructorKind
- : scopeRef->constructorKind();
- semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "super is not valid in this context");
- semanticFailIfTrue(functionConstructorKind != ConstructorKind::Derived, "super is not valid in this context");
- }
- if (functionScope->needsSuperBinding()) {
- ScopeRef scopeRef = closestParentOrdinaryFunctionNonLexicalScope();
- SuperBinding functionSuperBinding = functionBodyType == StandardFunctionBodyBlock && !scopeRef->isEvalContext()
- ? expectedSuperBinding
- : scopeRef->expectedSuperBinding();
- semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
- }
- }
JSTokenLocation location = JSTokenLocation(m_token.m_location);
functionInfo.endOffset = m_token.m_data.offset;
@@ -3932,11 +3914,22 @@
}
if (baseIsSuper) {
- ScopeRef scopeRef = closestParentOrdinaryFunctionNonLexicalScope();
- semanticFailIfFalse(currentScope()->isFunction() || (scopeRef->isEvalContext() && scopeRef->expectedSuperBinding() == SuperBinding::Needed), "super is not valid in this context");
+ ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+ semanticFailIfFalse(currentScope()->isFunction() || (closestOrdinaryFunctionScope->isEvalContext() && closestOrdinaryFunctionScope->expectedSuperBinding() == SuperBinding::Needed), "super is not valid in this context");
base = context.createSuperExpr(location);
next();
- currentFunctionScope()->setNeedsSuperBinding();
+ ScopeRef functionScope = currentFunctionScope();
+ if (!functionScope->setNeedsSuperBinding()) {
+ // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
+ // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
+ // inside of the constructor or method.
+ if (!m_lexer->isReparsingFunction()) {
+ SuperBinding functionSuperBinding = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
+ ? functionScope->expectedSuperBinding()
+ : closestOrdinaryFunctionScope->expectedSuperBinding();
+ semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
+ }
+ }
} else if (!baseIsNewTarget)
base = parsePrimaryExpression(context);
@@ -3975,9 +3968,22 @@
TreeArguments arguments = parseArguments(context);
failIfFalse(arguments, "Cannot parse call arguments");
if (baseIsSuper) {
- currentFunctionScope()->setHasDirectSuper();
+ ScopeRef functionScope = currentFunctionScope();
+ if (!functionScope->setHasDirectSuper()) {
+ // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
+ // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
+ // inside of the constructor or method.
+ if (!m_lexer->isReparsingFunction()) {
+ ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+ ConstructorKind functionConstructorKind = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
+ ? functionScope->constructorKind()
+ : closestOrdinaryFunctionScope->constructorKind();
+ semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "super is not valid in this context");
+ semanticFailIfTrue(functionConstructorKind != ConstructorKind::Derived, "super is not valid in this context");
+ }
+ }
if (currentScope()->isArrowFunction())
- currentFunctionScope()->setInnerArrowFunctionUsesSuperCall();
+ functionScope->setInnerArrowFunctionUsesSuperCall();
}
base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
}
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index 144545b..d5aa0cc 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -530,11 +530,11 @@
bool isArrowFunctionBoundary() { return m_isArrowFunctionBoundary; }
bool isArrowFunction() { return m_isArrowFunction; }
- bool hasDirectSuper() { return m_hasDirectSuper; }
- void setHasDirectSuper() { m_hasDirectSuper = true; }
+ bool hasDirectSuper() const { return m_hasDirectSuper; }
+ bool setHasDirectSuper() { return std::exchange(m_hasDirectSuper, true); }
- bool needsSuperBinding() { return m_needsSuperBinding; }
- void setNeedsSuperBinding() { m_needsSuperBinding = true; }
+ bool needsSuperBinding() const { return m_needsSuperBinding; }
+ bool setNeedsSuperBinding() { return std::exchange(m_needsSuperBinding, true); }
void setEvalContextType(EvalContextType evalContextType) { m_evalContextType = evalContextType; }
EvalContextType evalContextType() { return m_evalContextType; }
@@ -1034,6 +1034,7 @@
ASSERT(i < m_scopeStack.size() && m_scopeStack.size());
while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isArrowFunctionBoundary()))
i--;
+ // When reaching the top level scope (it can be non ordinary function scope), we return it.
return ScopeRef(&m_scopeStack, i);
}
diff --git a/Source/JavaScriptCore/tests/stress/eval-and-super.js b/Source/JavaScriptCore/tests/stress/eval-and-super.js
new file mode 100644
index 0000000..e09da93
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/eval-and-super.js
@@ -0,0 +1,37 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+
+
+class Hello {
+ m()
+ {
+ return eval("super()");
+ }
+
+ n()
+ {
+ return (0, eval)("super()");
+ }
+};
+
+var hello = new Hello();
+shouldThrow(() => hello.m(), `SyntaxError: super is not valid in this context.`);
+shouldThrow(() => hello.n(), `SyntaxError: super is not valid in this context.`);
diff --git a/Source/JavaScriptCore/tests/stress/generator-and-super.js b/Source/JavaScriptCore/tests/stress/generator-and-super.js
new file mode 100644
index 0000000..5ed5240
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-and-super.js
@@ -0,0 +1,42 @@
+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(`
+class Base {
+ hello()
+ {
+ print("Hello");
+ }
+
+ *ok()
+ {
+ super.hello();
+ }
+}
+
+class Hello extends Base {
+ *gen()
+ {
+ super();
+ }
+}
+`, `SyntaxError: super is not valid in this context.`);
+
+
+testSyntaxError(`
+function *hello()
+{
+ super.hello();
+}
+`, `SyntaxError: super is not valid in this context.`);