Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index 8b7f04e430705086888d98a5ccd300c5af3059af..f638069697c7788d223fce7a67333dc4fe8ed309 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -125,6 +125,27 @@ class BoolScope : public ValueObject { |
| }; |
| +class RecursionChecker : public ValueObject { |
| + public: |
| + explicit RecursionChecker(Parser* p) : parser_(p) { |
| + parser_->recursion_counter_++; |
| + // No need to check the stack unless the parser is in an unusually deep |
| + // recurive state. Thus, we omit the more expensive stack checks in |
| + // the common case. |
| + const int kMaxUncheckedDepth = 100; // Somewhat arbitrary. |
| + if (parser_->recursion_counter_ > kMaxUncheckedDepth) { |
| + parser_->CheckStack(); |
| + } |
| + } |
| + ~RecursionChecker() { |
| + parser_->recursion_counter_--; |
| + } |
| + |
| + private: |
| + Parser* parser_; |
| +}; |
| + |
| + |
| static RawTypeArguments* NewTypeArguments( |
| const GrowableArray<AbstractType*>& objs) { |
| const TypeArguments& a = |
| @@ -347,7 +368,8 @@ Parser::Parser(const Script& script, const Library& library, intptr_t token_pos) |
| last_used_try_index_(0), |
| unregister_pending_function_(false), |
| async_temp_scope_(NULL), |
| - trace_indent_(0) { |
| + trace_indent_(0), |
| + recursion_counter_(0) { |
| ASSERT(tokens_iterator_.IsValid()); |
| ASSERT(!library.IsNull()); |
| } |
| @@ -381,7 +403,8 @@ Parser::Parser(const Script& script, |
| last_used_try_index_(0), |
| unregister_pending_function_(false), |
| async_temp_scope_(NULL), |
| - trace_indent_(0) { |
| + trace_indent_(0), |
| + recursion_counter_(0) { |
| ASSERT(tokens_iterator_.IsValid()); |
| ASSERT(!current_function().IsNull()); |
| EnsureExpressionTemp(); |
| @@ -6112,6 +6135,17 @@ void Parser::ParseTopLevel() { |
| } |
| +void Parser::CheckStack() { |
| + volatile uword c_stack_pos = Isolate::GetCurrentStackPointer(); |
| + volatile uword c_stack_base = OSThread::Current()->stack_base(); |
| + volatile uword c_stack_limit = |
| + c_stack_base - OSThread::GetSpecifiedStackSize(); |
| + if ((c_stack_base > 0) && (c_stack_pos < c_stack_limit)) { |
|
rmacnak
2016/01/22 00:45:28
Add comment that c_stack_base > 0 handles the case
hausner
2016/01/22 18:38:14
Done.
|
| + ReportError("stack overflow while parsing"); |
| + } |
| +} |
| + |
| + |
| void Parser::ChainNewBlock(LocalScope* outer_scope) { |
| Block* block = new(Z) Block( |
| current_block_, |
| @@ -8058,6 +8092,7 @@ void Parser::ParseStatementSequence() { |
| TRACE_PARSER("ParseStatementSequence"); |
| const bool dead_code_allowed = true; |
| bool abrupt_completing_seen = false; |
| + RecursionChecker rc(this); |
| while (CurrentToken() != Token::kRBRACE) { |
| const intptr_t statement_pos = TokenPos(); |
| AstNode* statement = ParseStatement(); |
| @@ -8097,6 +8132,7 @@ SequenceNode* Parser::ParseNestedStatement(bool parsing_loop_body, |
| ParseStatementSequence(); |
| ExpectToken(Token::kRBRACE); |
| } else { |
| + RecursionChecker rc(this); |
| AstNode* statement = ParseStatement(); |
| if (statement != NULL) { |
| current_block_->statements->Add(statement); |
| @@ -10835,6 +10871,8 @@ AstNode* Parser::ParseExpr(bool require_compiletime_const, |
| Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
| const intptr_t expr_pos = TokenPos(); |
| + RecursionChecker rc(this); |
| + |
| if (CurrentToken() == Token::kTHROW) { |
| if (require_compiletime_const) { |
| ReportError("'throw expr' is not a valid compile-time constant"); |