Strict mode destructuring assignment crashes the parser.
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Mar 2014 01:54:01 +0000 (01:54 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Mar 2014 01:54:01 +0000 (01:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=130538

Reviewed by Michael Saboff.

Source/JavaScriptCore:

The SyntaxChecker mode always return 1 for success, except
for a small subset of functions where we needed exact information.
This ends up just being a poor design decision as it means
the parser can get confused between a function return 1, and
the Resolve constant which was also 1. So we now use a unique
type for every creation method.

* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createSourceElements):
(JSC::SyntaxChecker::createFunctionBody):
(JSC::SyntaxChecker::createArguments):
(JSC::SyntaxChecker::createSpreadExpression):
(JSC::SyntaxChecker::createArgumentsList):
(JSC::SyntaxChecker::createPropertyList):
(JSC::SyntaxChecker::createElementList):
(JSC::SyntaxChecker::createFormalParameterList):
(JSC::SyntaxChecker::createClause):
(JSC::SyntaxChecker::createClauseList):
(JSC::SyntaxChecker::createFuncDeclStatement):
(JSC::SyntaxChecker::createBlockStatement):
(JSC::SyntaxChecker::createExprStatement):
(JSC::SyntaxChecker::createIfStatement):
(JSC::SyntaxChecker::createForLoop):
(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
(JSC::SyntaxChecker::createEmptyStatement):
(JSC::SyntaxChecker::createVarStatement):
(JSC::SyntaxChecker::createReturnStatement):
(JSC::SyntaxChecker::createBreakStatement):
(JSC::SyntaxChecker::createContinueStatement):
(JSC::SyntaxChecker::createTryStatement):
(JSC::SyntaxChecker::createSwitchStatement):
(JSC::SyntaxChecker::createWhileStatement):
(JSC::SyntaxChecker::createWithStatement):
(JSC::SyntaxChecker::createDoWhileStatement):
(JSC::SyntaxChecker::createLabelStatement):
(JSC::SyntaxChecker::createThrowStatement):
(JSC::SyntaxChecker::createDebugger):
(JSC::SyntaxChecker::createConstStatement):
(JSC::SyntaxChecker::appendConstDecl):
(JSC::SyntaxChecker::combineCommaNodes):
(JSC::SyntaxChecker::operatorStackPop):

LayoutTests:

Add tests

* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:

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

LayoutTests/ChangeLog
LayoutTests/js/parser-syntax-check-expected.txt
LayoutTests/js/script-tests/parser-syntax-check.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/SyntaxChecker.h

index 54441b2..901e10a 100644 (file)
@@ -1,3 +1,15 @@
+2014-03-24  Oliver Hunt  <oliver@apple.com>
+
+        Strict mode destructuring assignment crashes the parser.
+        https://bugs.webkit.org/show_bug.cgi?id=130538
+
+        Reviewed by Michael Saboff.
+
+        Add tests
+
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+
 2014-03-24  Daniel Bates  <dabates@apple.com>
 
         XSS Auditor doesn't block <script> injected before an existing <script>
index f913759..7ed0b7f 100644 (file)
@@ -688,6 +688,24 @@ PASS Valid:   "({1: x})"
 PASS Valid:   "function f() { ({1: x}) }"
 PASS Valid:   "({1: x}=1)"
 PASS Valid:   "function f() { ({1: x}=1) }"
+PASS Valid:   "({1: x}=null)"
+PASS Valid:   "function f() { ({1: x}=null) }"
+PASS Valid:   "({1: x})"
+PASS Valid:   "function f() { ({1: x}) }"
+PASS Valid:   "({1: x}=1)"
+PASS Valid:   "function f() { ({1: x}=1) }"
+PASS Valid:   "({1: x}=null)"
+PASS Valid:   "function f() { ({1: x}=null) }"
+PASS Valid:   "({a: b}=null)"
+PASS Valid:   "function f() { ({a: b}=null) }"
+PASS Valid:   "'use strict'; ({1: x})"
+PASS Valid:   "function f() { 'use strict'; ({1: x}) }"
+PASS Valid:   "'use strict'; ({1: x}=1)"
+PASS Valid:   "function f() { 'use strict'; ({1: x}=1) }"
+PASS Valid:   "'use strict'; ({1: x}=null)"
+PASS Valid:   "function f() { 'use strict'; ({1: x}=null) }"
+PASS Valid:   "'use strict'; ({a: b}=null)"
+PASS Valid:   "function f() { 'use strict'; ({a: b}=null) }"
 PASS Valid:   "var {1:x}=1"
 PASS Valid:   "function f() { var {1:x}=1 }"
 PASS Valid:   "[x]=1"
index 6e91d52..c6f934c 100644 (file)
@@ -427,6 +427,15 @@ valid("[...bar,,,,]")
 valid("[,,,,...bar]")
 valid("({1: x})")
 valid("({1: x}=1)")
+valid("({1: x}=null)")
+valid("({1: x})")
+valid("({1: x}=1)")
+valid("({1: x}=null)")
+valid("({a: b}=null)")
+valid("'use strict'; ({1: x})")
+valid("'use strict'; ({1: x}=1)")
+valid("'use strict'; ({1: x}=null)")
+valid("'use strict'; ({a: b}=null)")
 valid("var {1:x}=1")
 valid("[x]=1")
 valid("var [x]=1")
index 7751ae5..288acf5 100644 (file)
@@ -1,3 +1,53 @@
+2014-03-24  Oliver Hunt  <oliver@apple.com>
+
+        Strict mode destructuring assignment crashes the parser.
+        https://bugs.webkit.org/show_bug.cgi?id=130538
+
+        Reviewed by Michael Saboff.
+
+        The SyntaxChecker mode always return 1 for success, except
+        for a small subset of functions where we needed exact information.
+        This ends up just being a poor design decision as it means
+        the parser can get confused between a function return 1, and
+        the Resolve constant which was also 1. So we now use a unique
+        type for every creation method.
+
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createSourceElements):
+        (JSC::SyntaxChecker::createFunctionBody):
+        (JSC::SyntaxChecker::createArguments):
+        (JSC::SyntaxChecker::createSpreadExpression):
+        (JSC::SyntaxChecker::createArgumentsList):
+        (JSC::SyntaxChecker::createPropertyList):
+        (JSC::SyntaxChecker::createElementList):
+        (JSC::SyntaxChecker::createFormalParameterList):
+        (JSC::SyntaxChecker::createClause):
+        (JSC::SyntaxChecker::createClauseList):
+        (JSC::SyntaxChecker::createFuncDeclStatement):
+        (JSC::SyntaxChecker::createBlockStatement):
+        (JSC::SyntaxChecker::createExprStatement):
+        (JSC::SyntaxChecker::createIfStatement):
+        (JSC::SyntaxChecker::createForLoop):
+        (JSC::SyntaxChecker::createForInLoop):
+        (JSC::SyntaxChecker::createForOfLoop):
+        (JSC::SyntaxChecker::createEmptyStatement):
+        (JSC::SyntaxChecker::createVarStatement):
+        (JSC::SyntaxChecker::createReturnStatement):
+        (JSC::SyntaxChecker::createBreakStatement):
+        (JSC::SyntaxChecker::createContinueStatement):
+        (JSC::SyntaxChecker::createTryStatement):
+        (JSC::SyntaxChecker::createSwitchStatement):
+        (JSC::SyntaxChecker::createWhileStatement):
+        (JSC::SyntaxChecker::createWithStatement):
+        (JSC::SyntaxChecker::createDoWhileStatement):
+        (JSC::SyntaxChecker::createLabelStatement):
+        (JSC::SyntaxChecker::createThrowStatement):
+        (JSC::SyntaxChecker::createDebugger):
+        (JSC::SyntaxChecker::createConstStatement):
+        (JSC::SyntaxChecker::appendConstDecl):
+        (JSC::SyntaxChecker::combineCommaNodes):
+        (JSC::SyntaxChecker::operatorStackPop):
+
 2014-03-24  Brent Fulgham  <bfulgham@apple.com>
 
         Activate WebVTT Tests Once Merging is Complete
index 021e128..8912d8b 100644 (file)
@@ -75,7 +75,13 @@ public:
         FunctionExpr, BracketExpr, DotExpr, CallExpr,
         NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
         ConditionalExpr, AssignmentExpr, TypeofExpr,
-        DeleteExpr, ArrayLiteralExpr };
+        DeleteExpr, ArrayLiteralExpr, BindingDeconstruction,
+        ArrayDeconstruction, ObjectDeconstruction, SourceElementsResult,
+        FunctionBodyResult, SpreadExpr, ArgumentsResult,
+        PropertyListResult, ArgumentsListResult, ElementsListResult,
+        StatementResult, FormalParameterListResult, ClauseResult,
+        ClauseListResult, CommaExpr, DeconstructingAssignment
+    };
     typedef int ExpressionType;
 
     typedef ExpressionType Expression;
@@ -111,7 +117,6 @@ public:
     typedef int Clause;
     typedef int ConstDeclList;
     typedef int BinaryOperand;
-    enum { BindingDeconstruction = 1, ArrayDeconstruction, ObjectDeconstruction };
     typedef int DeconstructionPattern;
     typedef DeconstructionPattern ArrayPattern;
     typedef DeconstructionPattern ObjectPattern;
@@ -122,7 +127,7 @@ public:
     static const unsigned DontBuildKeywords = LexexFlagsDontBuildKeywords;
     static const unsigned DontBuildStrings = LexerFlagsDontBuildStrings;
 
-    int createSourceElements() { return 1; }
+    int createSourceElements() { return SourceElementsResult; }
     ExpressionType makeFunctionCallNode(const JSTokenLocation&, int, int, int, int, int) { return CallExpr; }
     void appendToComma(ExpressionType& base, ExpressionType right) { base = right; }
     ExpressionType createCommaExpr(const JSTokenLocation&, ExpressionType, ExpressionType right) { return right; }
@@ -154,13 +159,13 @@ public:
     ExpressionType createConditionalExpr(const JSTokenLocation&, ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
     ExpressionType createAssignResolve(const JSTokenLocation&, const Identifier&, ExpressionType, int, int, int) { return AssignmentExpr; }
     ExpressionType createFunctionExpr(const JSTokenLocation&, const Identifier*, int, int, int, int, int, int, int) { return FunctionExpr; }
-    int createFunctionBody(const JSTokenLocation&, const JSTokenLocation&, int, int, bool) { return 1; }
+    int createFunctionBody(const JSTokenLocation&, const JSTokenLocation&, int, int, bool) { return FunctionBodyResult; }
     void setFunctionNameStart(int, int) { }
-    int createArguments() { return 1; }
-    int createArguments(int) { return 1; }
-    ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return 1; }
-    int createArgumentsList(const JSTokenLocation&, int) { return 1; }
-    int createArgumentsList(const JSTokenLocation&, int, int) { return 1; }
+    int createArguments() { return ArgumentsResult; }
+    int createArguments(int) { return ArgumentsResult; }
+    ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return SpreadExpr; }
+    int createArgumentsList(const JSTokenLocation&, int) { return ArgumentsListResult; }
+    int createArgumentsList(const JSTokenLocation&, int, int) { return ArgumentsListResult; }
     Property createProperty(const Identifier* name, int, PropertyNode::Type type, bool complete)
     {
         if (!complete)
@@ -178,41 +183,41 @@ public:
     {
         return Property(type);
     }
-    int createPropertyList(const JSTokenLocation&, Property) { return 1; }
-    int createPropertyList(const JSTokenLocation&, Property, int) { return 1; }
-    int createElementList(int, int) { return 1; }
-    int createElementList(int, int, int) { return 1; }
-    int createFormalParameterList(DeconstructionPattern) { return 1; }
-    int createFormalParameterList(int, DeconstructionPattern) { return 1; }
-    int createClause(int, int) { return 1; }
-    int createClauseList(int) { return 1; }
-    int createClauseList(int, int) { return 1; }
+    int createPropertyList(const JSTokenLocation&, Property) { return PropertyListResult; }
+    int createPropertyList(const JSTokenLocation&, Property, int) { return PropertyListResult; }
+    int createElementList(int, int) { return ElementsListResult; }
+    int createElementList(int, int, int) { return ElementsListResult; }
+    int createFormalParameterList(DeconstructionPattern) { return FormalParameterListResult; }
+    int createFormalParameterList(int, DeconstructionPattern) { return FormalParameterListResult; }
+    int createClause(int, int) { return ClauseResult; }
+    int createClauseList(int) { return ClauseListResult; }
+    int createClauseList(int, int) { return ClauseListResult; }
     void setUsesArguments(int) { }
-    int createFuncDeclStatement(const JSTokenLocation&, const Identifier*, int, int, int, int, int, int, int) { return 1; }
-    int createBlockStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int createExprStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int createIfStatement(const JSTokenLocation&, int, int, int, int) { return 1; }
-    int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return 1; }
-    int createForLoop(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
-    int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
-    int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
-    int createEmptyStatement(const JSTokenLocation&) { return 1; }
-    int createVarStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int createReturnStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int createBreakStatement(const JSTokenLocation&, int, int) { return 1; }
-    int createBreakStatement(const JSTokenLocation&, const Identifier*, int, int) { return 1; }
-    int createContinueStatement(const JSTokenLocation&, int, int) { return 1; }
-    int createContinueStatement(const JSTokenLocation&, const Identifier*, int, int) { return 1; }
-    int createTryStatement(const JSTokenLocation&, int, const Identifier*, int, int, int, int) { return 1; }
-    int createSwitchStatement(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
-    int createWhileStatement(const JSTokenLocation&, int, int, int, int) { return 1; }
-    int createWithStatement(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
-    int createDoWhileStatement(const JSTokenLocation&, int, int, int, int) { return 1; }
-    int createLabelStatement(const JSTokenLocation&, const Identifier*, int, int, int) { return 1; }
-    int createThrowStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int createDebugger(const JSTokenLocation&, int, int) { return 1; }
-    int createConstStatement(const JSTokenLocation&, int, int, int) { return 1; }
-    int appendConstDecl(const JSTokenLocation&, int, const Identifier*, int) { return 1; }
+    int createFuncDeclStatement(const JSTokenLocation&, const Identifier*, int, int, int, int, int, int, int) { return StatementResult; }
+    int createBlockStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createExprStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createIfStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+    int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return StatementResult; }
+    int createForLoop(const JSTokenLocation&, int, int, int, int, int, int) { return StatementResult; }
+    int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return StatementResult; }
+    int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return StatementResult; }
+    int createEmptyStatement(const JSTokenLocation&) { return StatementResult; }
+    int createVarStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createReturnStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createBreakStatement(const JSTokenLocation&, int, int) { return StatementResult; }
+    int createBreakStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
+    int createContinueStatement(const JSTokenLocation&, int, int) { return StatementResult; }
+    int createContinueStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
+    int createTryStatement(const JSTokenLocation&, int, const Identifier*, int, int, int, int) { return StatementResult; }
+    int createSwitchStatement(const JSTokenLocation&, int, int, int, int, int, int) { return StatementResult; }
+    int createWhileStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+    int createWithStatement(const JSTokenLocation&, int, int, int, int, int, int) { return StatementResult; }
+    int createDoWhileStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+    int createLabelStatement(const JSTokenLocation&, const Identifier*, int, int, int) { return StatementResult; }
+    int createThrowStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createDebugger(const JSTokenLocation&, int, int) { return StatementResult; }
+    int createConstStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int appendConstDecl(const JSTokenLocation&, int, const Identifier*, int) { return StatementResult; }
     Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, bool strict, const Identifier* name, int, int, int, int, int, int, int)
     {
         ASSERT(name);
@@ -229,7 +234,7 @@ public:
 
     void appendStatement(int, int) { }
     void addVar(const Identifier*, bool) { }
-    int combineCommaNodes(const JSTokenLocation&, int, int) { return 1; }
+    int combineCommaNodes(const JSTokenLocation&, int, int) { return CommaExpr; }
     int evalCount() const { return 0; }
     void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool)
     {
@@ -255,13 +260,13 @@ public:
     void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
     
     void assignmentStackAppend(int, int, int, int, int, Operator) { }
-    int createAssignment(const JSTokenLocation&, int, int, int, int, int) { RELEASE_ASSERT_NOT_REACHED(); return 1; }
+    int createAssignment(const JSTokenLocation&, int, int, int, int, int) { RELEASE_ASSERT_NOT_REACHED(); return AssignmentExpr; }
     const Identifier* getName(const Property& property) const { ASSERT(property.name); return property.name; }
     PropertyNode::Type getType(const Property& property) const { return property.type; }
     bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
     ExpressionType createDeconstructingAssignment(const JSTokenLocation&, int, ExpressionType)
     {
-        return 1;
+        return DeconstructingAssignment;
     }
     
     ArrayPattern createArrayPattern(const JSTokenLocation&)