Commit 526b7fc9 authored by Victor Zverovich's avatar Victor Zverovich

Throw exception in parse_nonnegative_int if the number is too big.

parent 9646e38c
......@@ -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 == '{') {
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment