mirror of
https://github.com/fmtlib/fmt.git
synced 2025-03-15 16:20:59 +00:00
Throw exception in parse_nonnegative_int if the number is too big.
This commit is contained in:
parent
9646e38c3b
commit
526b7fc91d
33
format.cc
33
format.cc
@ -160,20 +160,20 @@ class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
|
||||
// Parses an unsigned integer advancing s to the end of the parsed input.
|
||||
// This function assumes that the first character of s is a digit.
|
||||
template <typename Char>
|
||||
int parse_nonnegative_int(
|
||||
const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
|
||||
int parse_nonnegative_int(const Char *&s) {
|
||||
assert('0' <= *s && *s <= '9');
|
||||
unsigned value = 0;
|
||||
do {
|
||||
unsigned new_value = value * 10 + (*s++ - '0');
|
||||
// Check if value wrapped around.
|
||||
value = new_value >= value ? new_value : UINT_MAX;
|
||||
if (new_value < value) {
|
||||
value = UINT_MAX;
|
||||
break;
|
||||
}
|
||||
value = new_value;
|
||||
} while ('0' <= *s && *s <= '9');
|
||||
if (value > INT_MAX) {
|
||||
if (!error)
|
||||
error = "number is too big in format";
|
||||
return 0;
|
||||
}
|
||||
if (value > INT_MAX)
|
||||
throw fmt::FormatError("number is too big in format");
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -751,8 +751,7 @@ void fmt::BasicWriter<Char>::write_str(
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline const Arg
|
||||
&fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
||||
inline const Arg &fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
||||
const Arg *arg = 0;
|
||||
const char *error = 0;
|
||||
if (*s < '0' || *s > '9') {
|
||||
@ -761,11 +760,11 @@ inline const Arg
|
||||
if (next_arg_index_ > 0)
|
||||
error = "cannot switch from automatic to manual argument indexing";
|
||||
next_arg_index_ = -1;
|
||||
unsigned arg_index = parse_nonnegative_int(s, error);
|
||||
unsigned arg_index = parse_nonnegative_int(s);
|
||||
if (arg_index < args_.size())
|
||||
arg = &args_[arg_index];
|
||||
else if (!error)
|
||||
error = "argument index is out of range in format";
|
||||
error = "argument index is out of range in format";
|
||||
}
|
||||
if (error)
|
||||
throw FormatError(*s != '}' && *s != ':' ? "invalid format string" : error);
|
||||
@ -851,7 +850,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
unsigned value = parse_nonnegative_int(s, error_);
|
||||
unsigned value = parse_nonnegative_int(s);
|
||||
if (*s == '$') { // value is an argument index
|
||||
++s;
|
||||
arg_index = value;
|
||||
@ -869,7 +868,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
|
||||
parse_flags(spec, s);
|
||||
// Parse width.
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
spec.width_ = parse_nonnegative_int(s, error_);
|
||||
spec.width_ = parse_nonnegative_int(s);
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX));
|
||||
@ -916,7 +915,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
||||
if (*s == '.') {
|
||||
++s;
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
spec.precision_ = parse_nonnegative_int(s, error_);
|
||||
spec.precision_ = parse_nonnegative_int(s);
|
||||
} else if (*s == '*') {
|
||||
++s;
|
||||
spec.precision_ = PrecisionHandler().visit(handle_arg_index(UINT_MAX));
|
||||
@ -1132,7 +1131,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
}
|
||||
// Zero may be parsed again as a part of the width, but it is simpler
|
||||
// and more efficient than checking if the next char is a digit.
|
||||
spec.width_ = parse_nonnegative_int(s, error);
|
||||
spec.width_ = parse_nonnegative_int(s);
|
||||
if (error)
|
||||
throw FormatError(error);
|
||||
}
|
||||
@ -1142,7 +1141,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
++s;
|
||||
spec.precision_ = 0;
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
spec.precision_ = parse_nonnegative_int(s, error);
|
||||
spec.precision_ = parse_nonnegative_int(s);
|
||||
if (error)
|
||||
throw FormatError(error);
|
||||
} else if (*s == '{') {
|
||||
|
2
format.h
2
format.h
@ -883,7 +883,7 @@ private:
|
||||
BasicWriter<Char> &writer_;
|
||||
const Char *start_;
|
||||
|
||||
// Parses argument index and returns an argument with this index.
|
||||
// Parses argument index and returns corresponding argument.
|
||||
const internal::Arg &parse_arg_index(const Char *&s);
|
||||
|
||||
void check_sign(const Char *&s, const internal::Arg &arg);
|
||||
|
@ -619,7 +619,8 @@ TEST(FormatterTest, ArgErrors) {
|
||||
"argument index is out of range in format");
|
||||
|
||||
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
||||
EXPECT_THROW_MSG(format(format_str), FormatError, "invalid format string");
|
||||
EXPECT_THROW_MSG(format(format_str), FormatError,
|
||||
"number is too big in format");
|
||||
safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
|
||||
EXPECT_THROW_MSG(format(format_str), FormatError,
|
||||
"number is too big in format");
|
||||
@ -1002,7 +1003,8 @@ TEST(FormatterTest, RuntimePrecision) {
|
||||
char format_str[BUFFER_SIZE];
|
||||
safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
|
||||
increment(format_str + 5);
|
||||
EXPECT_THROW_MSG(format(format_str, 0), FormatError, "invalid format string");
|
||||
EXPECT_THROW_MSG(format(format_str, 0), FormatError,
|
||||
"number is too big in format");
|
||||
std::size_t size = std::strlen(format_str);
|
||||
format_str[size] = '}';
|
||||
format_str[size + 1] = 0;
|
||||
|
@ -79,7 +79,7 @@ TEST(PrintfTest, AutomaticArgIndexing) {
|
||||
|
||||
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)),
|
||||
FormatError, "invalid format string");
|
||||
FormatError, "number is too big in format");
|
||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)),
|
||||
FormatError, "number is too big in format");
|
||||
}
|
||||
@ -429,3 +429,13 @@ TEST(PrintfTest, Pointer) {
|
||||
TEST(PrintfTest, Location) {
|
||||
// TODO: test %n
|
||||
}
|
||||
|
||||
#if FMT_USE_FILE_DESCRIPTORS
|
||||
TEST(PrintfTest, Examples) {
|
||||
const char *weekday = "Thursday";
|
||||
const char *month = "August";
|
||||
int day = 21;
|
||||
EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
|
||||
"Thursday, 21 August");
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user