Просмотр исходного кода

Limit the number of parsed digits in numeric literals (#979)

Jon Meow 4 лет назад
Родитель
Сommit
90c58dae2b

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
toolchain/lexer/fuzzer_corpus/numeric_literal/a6c9027065d9ae3dc8f1b1b880d5f1775240ca0c


BIN
toolchain/lexer/fuzzer_corpus/tokenized_buffer/eec540334e2254864e033353ec23daa556fadcd0


+ 30 - 0
toolchain/lexer/numeric_literal.cpp

@@ -80,6 +80,21 @@ struct WrongRealLiteralExponent {
 
   char expected;
 };
+
+struct TooManyDigits {
+  static constexpr llvm::StringLiteral ShortName = "syntax-invalid-number";
+
+  auto Format() -> std::string {
+    return llvm::formatv(
+               "Found a sequence of {0} digits, which is greater than the "
+               "limit of {1}.",
+               count, limit)
+        .str();
+  }
+
+  size_t count;
+  size_t limit;
+};
 }  // namespace
 
 auto LexedNumericLiteral::Lex(llvm::StringRef source_text)
@@ -366,6 +381,21 @@ auto LexedNumericLiteral::Parser::CheckDigitSequence(
     CheckDigitSeparatorPlacement(text, radix, num_digit_separators);
   }
 
+  // llvm::getAsInteger is used for parsing, but it's quadratic and visibly slow
+  // on large integer values. This limit exists to avoid hitting those limits.
+  // Per https://github.com/carbon-language/carbon-lang/issues/980, it may be
+  // feasible to optimize integer parsing in order to address performance if
+  // this limit becomes an issue.
+  //
+  // 2^128 would be 39 decimal digits or 128 binary. In either case, this limit
+  // is far above the threshold for normal integers.
+  constexpr size_t DigitLimit = 1000;
+  if (text.size() > DigitLimit) {
+    emitter_.EmitError<TooManyDigits>(
+        text.begin(), {.count = text.size(), .limit = DigitLimit});
+    return {.ok = false};
+  }
+
   return {.ok = true, .has_digit_separators = (num_digit_separators != 0)};
 }
 

+ 6 - 0
toolchain/lexer/numeric_literal_test.cpp

@@ -331,5 +331,11 @@ TEST_F(NumericLiteralTest, ValidatesRealLiterals) {
   }
 }
 
+TEST_F(NumericLiteralTest, TooManyDigits) {
+  std::string long_number(2000, '1');
+  EXPECT_THAT(Parse(long_number), HasUnrecoverableError());
+  EXPECT_TRUE(error_tracker.SeenError());
+}
+
 }  // namespace
 }  // namespace Carbon

Некоторые файлы не были показаны из-за большого количества измененных файлов