mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 06:21:32 +00:00
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 .
This commit is contained in:
parent
9ce608e89d
commit
62320cc838
|
@ -57,5 +57,6 @@
|
|||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="application" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -437,6 +437,7 @@ const List<ErrorCode> 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,
|
||||
|
|
|
@ -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'.",
|
||||
|
|
|
@ -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<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 (labels == null) {
|
||||
labels = <Label>[label];
|
||||
} else {
|
||||
labels.add(label);
|
||||
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) {
|
||||
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 {}
|
||||
|
|
|
@ -14,8 +14,8 @@ regress_29025_test: StaticWarning # Issue 29081
|
|||
# Runtime negative test. No static errors or warnings.
|
||||
closure_call_wrong_argument_count_negative_test: skip
|
||||
|
||||
deep_nesting1_negative_test: Crash # Issue 25558
|
||||
deep_nesting2_negative_test: Crash # Issue 25558
|
||||
deep_nesting1_negative_test: CompileTimeError # Issue 25558
|
||||
deep_nesting2_negative_test: CompileTimeError # Issue 25558
|
||||
|
||||
enum_syntax_test/05: Fail # 21649
|
||||
enum_syntax_test/06: Fail # 21649
|
||||
|
|
Loading…
Reference in a new issue