From a80d668a52a92b67e01cdf59622454b31c4059c3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Jul 2024 09:54:40 -0700 Subject: [PATCH] Diagnose invalid precision --- include/fmt/base.h | 42 ++++++++++++++++++++---------------------- include/fmt/chrono.h | 14 ++++++++++---- include/fmt/std.h | 4 +++- test/format-test.cc | 4 +++- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/include/fmt/base.h b/include/fmt/base.h index e29ff140..09668925 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2323,7 +2323,7 @@ template struct dynamic_spec_id_handler { } }; -// Parses [integer | "{" [arg_id] "}"]. +// Parses integer | "{" [arg_id] "}". template FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, int& value, arg_ref& ref, @@ -2332,24 +2332,24 @@ FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, FMT_ASSERT(begin != end, ""); if ('0' <= *begin && *begin <= '9') { int val = parse_nonnegative_int(begin, end, -1); - if (val != -1) - value = val; - else - report_error("number is too big"); - } else if (*begin == '{') { - ++begin; - if (begin != end) { - Char c = *begin; - if (c == '}' || c == ':') { - int id = ctx.next_arg_id(); - ref = arg_ref(id); - ctx.check_dynamic_spec(id); - } else { - begin = - parse_arg_id(begin, end, dynamic_spec_id_handler{ctx, ref}); + if (val == -1) report_error("number is too big"); + value = val; + } else { + if (*begin == '{') { + ++begin; + if (begin != end) { + Char c = *begin; + if (c == '}' || c == ':') { + int id = ctx.next_arg_id(); + ref = arg_ref(id); + ctx.check_dynamic_spec(id); + } else { + begin = + parse_arg_id(begin, end, dynamic_spec_id_handler{ctx, ref}); + } } + if (begin != end && *begin == '}') return ++begin; } - if (begin != end && *begin == '}') return ++begin; report_error("invalid format string"); } return begin; @@ -2361,11 +2361,9 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, basic_format_parse_context& ctx) -> const Char* { ++begin; - if (begin == end || *begin == '}') { - report_error("invalid precision"); - return begin; - } - return parse_dynamic_spec(begin, end, value, ref, ctx); + if (begin != end) begin = parse_dynamic_spec(begin, end, value, ref, ctx); + else report_error("invalid precision"); + return begin; } enum class state { start, align, sign, hash, zero, width, precision, locale }; diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index c01e4b14..76af8c24 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -2251,8 +2251,11 @@ struct formatter, Char> { it = detail::parse_align(it, end, specs_); if (it == end) return it; - it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); - if (it == end) return it; + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') { + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + } auto checker = detail::chrono_format_checker(); if (*it == '.') { @@ -2410,8 +2413,11 @@ template struct formatter { it = detail::parse_align(it, end, specs_); if (it == end) return it; - it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); - if (it == end) return it; + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') { + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + } end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); // Replace the default format_str only if the new spec is not empty. diff --git a/include/fmt/std.h b/include/fmt/std.h index fb43940b..0695460c 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -129,7 +129,9 @@ template struct formatter { it = detail::parse_align(it, end, specs_); if (it == end) return it; - it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); if (it != end && *it == '?') { debug_ = true; ++it; diff --git a/test/format-test.cc b/test/format-test.cc index a018b9f7..86c70981 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -945,7 +945,7 @@ TEST(format_test, precision) { EXPECT_THROW_MSG((void)fmt::format(runtime("{0:."), 0.0), format_error, "invalid precision"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.}"), 0.0), format_error, - "invalid precision"); + "invalid format string"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2"), 0), format_error, "invalid format specifier"); @@ -1066,6 +1066,8 @@ TEST(format_test, precision) { EXPECT_THROW_MSG( (void)fmt::format("{:.2147483646f}", -2.2121295195081227E+304), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:.f}"), 42.0), format_error, + "invalid format string"); EXPECT_EQ(fmt::format("{0:.2}", "str"), "st"); EXPECT_EQ(fmt::format("{0:.5}", "вожыкі"), "вожык");