Change SkipRestOfBlock to be iterative instead of recursive to avoid stack

overflows on invalid input with many unbalanced `{` characters.

PiperOrigin-RevId: 562806350
pull/13857/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent 91114633bb
commit f75a800be0
  1. 6
      src/google/protobuf/compiler/parser.cc
  2. 18
      src/google/protobuf/compiler/parser_unittest.cc

@ -38,6 +38,7 @@
#include <float.h>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
@ -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();

@ -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<io::ArrayInputStream>(text, strlen(text));
void SetupParser(absl::string_view text) {
raw_input_ =
absl::make_unique<io::ArrayInputStream>(text.data(), text.size());
input_ =
absl::make_unique<io::Tokenizer>(raw_input_.get(), &error_collector_);
parser_ = absl::make_unique<Parser>();
@ -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;

Loading…
Cancel
Save