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"); |