From 62320cc8388fd4f18dfd3125abcc6c47a652be82 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Mon, 17 Apr 2017 14:46:52 -0700 Subject: [PATCH] Issue 25558. Report an error, but don't crash when AST it too deep. R=brianwilkerson@google.com BUG= https://github.com/dart-lang/sdk/issues/25558 Review-Url: https://codereview.chromium.org/2823993002 . --- pkg/analysis_server/analysis_server.iml | 1 + pkg/analyzer/lib/error/error.dart | 1 + .../lib/src/dart/error/syntactic_errors.dart | 5 + pkg/analyzer/lib/src/generated/parser.dart | 126 ++++++++++++------ tests/language/language_analyzer2.status | 4 +- 5 files changed, 92 insertions(+), 45 deletions(-) diff --git a/pkg/analysis_server/analysis_server.iml b/pkg/analysis_server/analysis_server.iml index ea34ce549c3..eeb9c7a6ff4 100644 --- a/pkg/analysis_server/analysis_server.iml +++ b/pkg/analysis_server/analysis_server.iml @@ -57,5 +57,6 @@ + \ No newline at end of file diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index 0b6aa79dde6..524f0cea7a4 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -437,6 +437,7 @@ const List errorCodeValues = const [ ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, ParserErrorCode.SETTER_IN_FUNCTION, + ParserErrorCode.STACK_OVERFLOW, ParserErrorCode.STATIC_AFTER_CONST, ParserErrorCode.STATIC_AFTER_FINAL, ParserErrorCode.STATIC_AFTER_VAR, diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart index c4b6f316e6d..35aab587527 100644 --- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart +++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart @@ -834,6 +834,11 @@ class ParserErrorCode extends ErrorCode { "Setters can't be defined within methods or functions.", "Try moving the setter outside the method or function."); + static const ParserErrorCode STACK_OVERFLOW = const ParserErrorCode( + 'STACK_OVERFLOW', + "The file has too many nested expressions or statements.", + "Try simplifying the code."); + static const ParserErrorCode STATIC_AFTER_CONST = const ParserErrorCode( 'STATIC_AFTER_CONST', "The modifier 'static' should be before the modifier 'const'.", diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart index 33eba26d683..ea41c985f8a 100644 --- a/pkg/analyzer/lib/src/generated/parser.dart +++ b/pkg/analyzer/lib/src/generated/parser.dart @@ -170,6 +170,8 @@ class Parser { static String _YIELD = Keyword.YIELD.syntax; + static const int _MAX_TREE_DEPTH = 300; + /** * The source being parsed. */ @@ -214,6 +216,12 @@ class Parser { */ Token _currentToken; + /** + * The depth of the current AST. When this depth is too high, so we're at the + * risk of overflowing the stack, we stop parsing and report an error. + */ + int _treeDepth = 0; + /** * A flag indicating whether the parser is currently in a function body marked * as being 'async'. @@ -1960,8 +1968,16 @@ class Parser { [_currentToken.lexeme]); _advance(); } else { - CompilationUnitMember member = - parseCompilationUnitMember(commentAndMetadata); + CompilationUnitMember member; + try { + member = parseCompilationUnitMember(commentAndMetadata); + } on _TooDeepTreeError { + _reportErrorForToken(ParserErrorCode.STACK_OVERFLOW, _currentToken); + Token eof = new Token(TokenType.EOF, 0); + eof.previous = eof; + eof.setNext(eof); + return astFactory.compilationUnit(eof, null, null, null, eof); + } if (member != null) { declarations.add(member); } @@ -2712,37 +2728,45 @@ class Parser { * | throwExpression */ Expression parseExpression2() { - Keyword keyword = _currentToken.keyword; - if (keyword == Keyword.THROW) { - return parseThrowExpression(); - } else if (keyword == Keyword.RETHROW) { - // TODO(brianwilkerson) Rethrow is a statement again. - return parseRethrowExpression(); + if (_treeDepth > _MAX_TREE_DEPTH) { + throw new _TooDeepTreeError(); } - // - // assignableExpression is a subset of conditionalExpression, so we can - // parse a conditional expression and then determine whether it is followed - // by an assignmentOperator, checking for conformance to the restricted - // grammar after making that determination. - // - Expression expression = parseConditionalExpression(); - TokenType type = _currentToken.type; - if (type == TokenType.PERIOD_PERIOD) { - List cascadeSections = []; - do { - Expression section = parseCascadeSection(); - if (section != null) { - cascadeSections.add(section); - } - } while (_currentToken.type == TokenType.PERIOD_PERIOD); - return astFactory.cascadeExpression(expression, cascadeSections); - } else if (type.isAssignmentOperator) { - Token operator = getAndAdvance(); - _ensureAssignable(expression); - return astFactory.assignmentExpression( - expression, operator, parseExpression2()); + _treeDepth++; + try { + Keyword keyword = _currentToken.keyword; + if (keyword == Keyword.THROW) { + return parseThrowExpression(); + } else if (keyword == Keyword.RETHROW) { + // TODO(brianwilkerson) Rethrow is a statement again. + return parseRethrowExpression(); + } + // + // assignableExpression is a subset of conditionalExpression, so we can + // parse a conditional expression and then determine whether it is followed + // by an assignmentOperator, checking for conformance to the restricted + // grammar after making that determination. + // + Expression expression = parseConditionalExpression(); + TokenType type = _currentToken.type; + if (type == TokenType.PERIOD_PERIOD) { + List cascadeSections = []; + do { + Expression section = parseCascadeSection(); + if (section != null) { + cascadeSections.add(section); + } + } while (_currentToken.type == TokenType.PERIOD_PERIOD); + return astFactory.cascadeExpression(expression, cascadeSections); + } else if (type.isAssignmentOperator) { + Token operator = getAndAdvance(); + _ensureAssignable(expression); + return astFactory.assignmentExpression( + expression, operator, parseExpression2()); + } + return expression; + } finally { + _treeDepth--; } - return expression; } /** @@ -4795,20 +4819,29 @@ class Parser { * label* nonLabeledStatement */ Statement parseStatement2() { - List