Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Unified Diff: pkg/analyzer/lib/src/generated/parser.dart

Issue 2823993002: Issue 25558. Report an error, but don't crash when AST it too deep. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/dart/error/syntactic_errors.dart ('k') | tests/language/language_analyzer2.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/parser.dart
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 33eba26d683875fa8ab9bdf729882c49f13f2e89..ea41c985f8a75d59658d1c4392f2600a62ac7507 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.
*/
@@ -215,6 +217,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<Expression> cascadeSections = <Expression>[];
- 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<Expression> cascadeSections = <Expression>[];
+ 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<Label> labels = null;
- while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
- Label label = parseLabel(isDeclaration: true);
+ if (_treeDepth > _MAX_TREE_DEPTH) {
+ throw new _TooDeepTreeError();
+ }
+ _treeDepth++;
+ try {
+ List<Label> labels = null;
+ while (
+ _matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
+ Label label = parseLabel(isDeclaration: true);
+ if (labels == null) {
+ labels = <Label>[label];
+ } else {
+ labels.add(label);
+ }
+ }
+ Statement statement = parseNonLabeledStatement();
if (labels == null) {
- labels = <Label>[label];
- } else {
- labels.add(label);
+ return statement;
}
+ return astFactory.labeledStatement(labels, statement);
+ } finally {
+ _treeDepth--;
}
- Statement statement = parseNonLabeledStatement();
- if (labels == null) {
- return statement;
- }
- return astFactory.labeledStatement(labels, statement);
}
/**
@@ -8567,3 +8600,10 @@ class Parser {
}
}
}
+
+/**
+ * Instances of this class are thrown when the parser detects that AST has
+ * too many nested expressions to be parsed safely and avoid possibility of
+ * [StackOverflowError] in the parser or during later analysis.
+ */
+class _TooDeepTreeError {}
« no previous file with comments | « pkg/analyzer/lib/src/dart/error/syntactic_errors.dart ('k') | tests/language/language_analyzer2.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698