diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 6620085c79..b6a3da8ce5 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -38,6 +38,7 @@ #include +#include #include #include #include @@ -555,14 +556,15 @@ void Parser::SkipStatement() { } void Parser::SkipRestOfBlock() { + size_t block_count = 1; while (true) { if (AtEnd()) { return; } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { if (TryConsumeEndOfDeclaration("}", nullptr)) { - return; + if (--block_count == 0) break; } else if (TryConsume("{")) { - SkipRestOfBlock(); + ++block_count; } } input_->Next(); diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 3c95a53e5f..429d9b2e3e 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -117,8 +117,9 @@ class ParserTest : public testing::Test { ParserTest() : require_syntax_identifier_(false) {} // Set up the parser to parse the given text. - void SetupParser(const char* text) { - raw_input_ = absl::make_unique(text, strlen(text)); + void SetupParser(absl::string_view text) { + raw_input_ = + absl::make_unique(text.data(), text.size()); input_ = absl::make_unique(raw_input_.get(), &error_collector_); parser_ = absl::make_unique(); @@ -169,7 +170,8 @@ class ParserTest : public testing::Test { // Same as above but does not expect that the parser parses the complete // input. - void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) { + void ExpectHasEarlyExitErrors(absl::string_view text, + absl::string_view expected_errors) { SetupParser(text); SourceLocationTable source_locations; parser_->RecordSourceLocationsTo(&source_locations); @@ -286,6 +288,16 @@ TEST_F(ParserTest, WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore) { "song_name_1.") != std::string::npos); } +TEST_F(ParserTest, RegressionNestedOpenBraceDoNotStackOverflow) { + std::string input("edition=\"a\000;", 12); + input += std::string(100000, '{'); + ExpectHasEarlyExitErrors( + input, + "0:10: Unexpected end of string.\n" + "0:10: Invalid control characters encountered in text.\n" + "0:12: Expected top-level statement (e.g. \"message\").\n"); +} + // =================================================================== typedef ParserTest ParseMessageTest;