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

This commit is contained in:
Jon Meow
2021-12-13 11:08:00 -08:00
committed by GitHub
parent e65e85b15d
commit 90c58dae2b
4 changed files with 37 additions and 0 deletions
File diff suppressed because one or more lines are too long
+30
View File
@@ -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
View File
@@ -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