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> { ...@@ -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. // 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. // This function assumes that the first character of s is a digit.
template <typename Char> template <typename Char>
int parse_nonnegative_int( int parse_nonnegative_int(const Char *&s) {
const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
assert('0' <= *s && *s <= '9'); assert('0' <= *s && *s <= '9');
unsigned value = 0; unsigned value = 0;
do { do {
unsigned new_value = value * 10 + (*s++ - '0'); unsigned new_value = value * 10 + (*s++ - '0');
// Check if value wrapped around. // Check if value wrapped around.
value = new_value >= value ? new_value : UINT_MAX; if (new_value < value) {
} while ('0' <= *s && *s <= '9'); value = UINT_MAX;
if (value > INT_MAX) { break;
if (!error)
error = "number is too big in format";
return 0;
} }
value = new_value;
} while ('0' <= *s && *s <= '9');
if (value > INT_MAX)
throw fmt::FormatError("number is too big in format");
return value; return value;
} }
...@@ -751,8 +751,7 @@ void fmt::BasicWriter<Char>::write_str( ...@@ -751,8 +751,7 @@ void fmt::BasicWriter<Char>::write_str(
} }
template <typename Char> template <typename Char>
inline const Arg inline const Arg &fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
&fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
const Arg *arg = 0; const Arg *arg = 0;
const char *error = 0; const char *error = 0;
if (*s < '0' || *s > '9') { if (*s < '0' || *s > '9') {
...@@ -761,7 +760,7 @@ inline const Arg ...@@ -761,7 +760,7 @@ inline const Arg
if (next_arg_index_ > 0) if (next_arg_index_ > 0)
error = "cannot switch from automatic to manual argument indexing"; error = "cannot switch from automatic to manual argument indexing";
next_arg_index_ = -1; next_arg_index_ = -1;
unsigned arg_index = parse_nonnegative_int(s, error); unsigned arg_index = parse_nonnegative_int(s);
if (arg_index < args_.size()) if (arg_index < args_.size())
arg = &args_[arg_index]; arg = &args_[arg_index];
else if (!error) else if (!error)
...@@ -851,7 +850,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header( ...@@ -851,7 +850,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly // Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s). // 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 if (*s == '$') { // value is an argument index
++s; ++s;
arg_index = value; arg_index = value;
...@@ -869,7 +868,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header( ...@@ -869,7 +868,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
parse_flags(spec, s); parse_flags(spec, s);
// Parse width. // Parse width.
if (*s >= '0' && *s <= '9') { if (*s >= '0' && *s <= '9') {
spec.width_ = parse_nonnegative_int(s, error_); spec.width_ = parse_nonnegative_int(s);
} else if (*s == '*') { } else if (*s == '*') {
++s; ++s;
spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX)); spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX));
...@@ -916,7 +915,7 @@ void fmt::internal::PrintfFormatter<Char>::format( ...@@ -916,7 +915,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (*s == '.') { if (*s == '.') {
++s; ++s;
if ('0' <= *s && *s <= '9') { if ('0' <= *s && *s <= '9') {
spec.precision_ = parse_nonnegative_int(s, error_); spec.precision_ = parse_nonnegative_int(s);
} else if (*s == '*') { } else if (*s == '*') {
++s; ++s;
spec.precision_ = PrecisionHandler().visit(handle_arg_index(UINT_MAX)); spec.precision_ = PrecisionHandler().visit(handle_arg_index(UINT_MAX));
...@@ -1132,7 +1131,7 @@ const Char *fmt::BasicFormatter<Char>::format( ...@@ -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 // 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. // 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) if (error)
throw FormatError(error); throw FormatError(error);
} }
...@@ -1142,7 +1141,7 @@ const Char *fmt::BasicFormatter<Char>::format( ...@@ -1142,7 +1141,7 @@ const Char *fmt::BasicFormatter<Char>::format(
++s; ++s;
spec.precision_ = 0; spec.precision_ = 0;
if ('0' <= *s && *s <= '9') { if ('0' <= *s && *s <= '9') {
spec.precision_ = parse_nonnegative_int(s, error); spec.precision_ = parse_nonnegative_int(s);
if (error) if (error)
throw FormatError(error); throw FormatError(error);
} else if (*s == '{') { } else if (*s == '{') {
......
...@@ -883,7 +883,7 @@ private: ...@@ -883,7 +883,7 @@ private:
BasicWriter<Char> &writer_; BasicWriter<Char> &writer_;
const Char *start_; 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); const internal::Arg &parse_arg_index(const Char *&s);
void check_sign(const Char *&s, const internal::Arg &arg); void check_sign(const Char *&s, const internal::Arg &arg);
......
...@@ -619,7 +619,8 @@ TEST(FormatterTest, ArgErrors) { ...@@ -619,7 +619,8 @@ TEST(FormatterTest, ArgErrors) {
"argument index is out of range in format"); "argument index is out of range in format");
safe_sprintf(format_str, "{%u", INT_MAX + 1u); 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); safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
EXPECT_THROW_MSG(format(format_str), FormatError, EXPECT_THROW_MSG(format(format_str), FormatError,
"number is too big in format"); "number is too big in format");
...@@ -1002,7 +1003,8 @@ TEST(FormatterTest, RuntimePrecision) { ...@@ -1002,7 +1003,8 @@ TEST(FormatterTest, RuntimePrecision) {
char format_str[BUFFER_SIZE]; char format_str[BUFFER_SIZE];
safe_sprintf(format_str, "{0:.{%u", UINT_MAX); safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
increment(format_str + 5); 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); std::size_t size = std::strlen(format_str);
format_str[size] = '}'; format_str[size] = '}';
format_str[size + 1] = 0; format_str[size + 1] = 0;
......
...@@ -79,7 +79,7 @@ TEST(PrintfTest, AutomaticArgIndexing) { ...@@ -79,7 +79,7 @@ TEST(PrintfTest, AutomaticArgIndexing) {
TEST(PrintfTest, NumberIsTooBigInArgIndex) { TEST(PrintfTest, NumberIsTooBigInArgIndex) {
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)), 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)), EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)),
FormatError, "number is too big in format"); FormatError, "number is too big in format");
} }
...@@ -429,3 +429,13 @@ TEST(PrintfTest, Pointer) { ...@@ -429,3 +429,13 @@ TEST(PrintfTest, Pointer) {
TEST(PrintfTest, Location) { TEST(PrintfTest, Location) {
// TODO: test %n // 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