From fc0c76a075b462ec0c01540536949c6db1308aee Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 1 Jun 2025 08:26:53 -0700 Subject: [PATCH] Handle large precision --- include/fmt/format.h | 4 ++-- test/format-test.cc | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 90fe56d7..beb81885 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2392,7 +2392,7 @@ FMT_CONSTEXPR20 auto write_fixed(OutputIt out, const DecimalFP& f, using iterator = reserve_iterator; int exp = f.exponent + significand_size; - int size = significand_size + (s != sign::none ? 1 : 0); + long long size = significand_size + (s != sign::none ? 1 : 0); if (f.exponent >= 0) { // 1234e5 -> 123400000[.0+] size += f.exponent; @@ -2466,7 +2466,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, // Write value in the exponential format. int num_zeros = 0; - int size = significand_size + (s != sign::none ? 1 : 0); + long long size = significand_size + (s != sign::none ? 1 : 0); if (specs.alt()) { num_zeros = max_of(specs.precision - significand_size, 0); size += num_zeros; diff --git a/test/format-test.cc b/test/format-test.cc index c0e1ea68..124b9bd2 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1095,9 +1095,6 @@ TEST(format_test, precision) { EXPECT_THROW_MSG( (void)fmt::format(runtime("{0:.2f}"), reinterpret_cast(0xcafe)), format_error, "invalid format specifier"); - EXPECT_THROW_MSG((void)fmt::format(runtime("{:.{}e}"), 42.0, - fmt::detail::max_value()), - format_error, "number is too big"); EXPECT_THROW_MSG( (void)fmt::format("{:.2147483646f}", -2.2121295195081227E+304), format_error, "number is too big"); @@ -1109,6 +1106,32 @@ TEST(format_test, precision) { EXPECT_EQ(fmt::format("{0:.6}", "123456\xad"), "123456"); } +TEST(format_test, large_precision) { + // Iterator used to abort the actual output. + struct throwing_iterator { + auto operator=(char) -> throwing_iterator& { + throw std::runtime_error("aborted"); + return *this; + } + auto operator*() -> throwing_iterator& { return *this; } + auto operator++() -> throwing_iterator& { return *this; } + auto operator++(int) -> throwing_iterator { return *this; } + }; + auto it = throwing_iterator(); + + EXPECT_THROW_MSG(fmt::format_to(it, fmt::runtime("{:#.{}}"), 1.0, + fmt::detail::max_value()), + std::runtime_error, "aborted"); + + EXPECT_THROW_MSG(fmt::format_to(it, fmt::runtime("{:#.{}e}"), 1.0, + fmt::detail::max_value() - 1), + std::runtime_error, "aborted"); + + EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:.{}e}"), 42.0, + fmt::detail::max_value()), + format_error, "number is too big"); +} + TEST(format_test, utf8_precision) { auto result = fmt::format("{:.4}", "caf\u00e9s"); // cafés EXPECT_EQ(fmt::detail::compute_width(result), 4);