mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Limit the number of parsed digits in numeric literals (#979)
This commit is contained in:
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
@@ -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)};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user