From d9f045fba18c6897ae0931a931450638560e3fd4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 9 Jan 2022 10:22:36 -0800 Subject: [PATCH] Fix a UB in chrono --- include/fmt/chrono.h | 20 +++++++++++++++++--- test/chrono-test.cc | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 682efd8d..c51aa8a0 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1663,7 +1663,7 @@ struct chrono_formatter { out = format_decimal(out, n, num_digits).end; } - template void write_fractional_seconds(Duration d) { + template void write_fractional_seconds(Duration d) { constexpr auto num_fractional_digits = count_fractional_digits(Duration::period::num, Duration::period::den); @@ -1770,8 +1770,22 @@ struct chrono_formatter { if (handle_nan_inf()) return; if (ns == numeric_system::standard) { - write(second(), 2); - write_fractional_seconds(std::chrono::duration{val}); + if (std::is_floating_point::value) { + auto num_fractional_digits = + count_fractional_digits(Period::num, Period::den); + auto buf = memory_buffer(); + format_to(std::back_inserter(buf), runtime("{:.{}f}"), + std::fmod(val * static_cast(Period::num) / + static_cast(Period::den), + 60), + num_fractional_digits); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') *out++ = '0'; + out = std::copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2); + write_fractional_seconds(std::chrono::duration(val)); + } return; } auto time = tm(); diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 42360e5f..6d7e6044 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -557,6 +557,9 @@ TEST(chrono_test, special_durations) { "03:33"); EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration{2}), "03:33:20"); + EXPECT_EQ("44.000000000000", + fmt::format("{:%S}", std::chrono::duration( + 1.54213895E+26))); } TEST(chrono_test, unsigned_duration) {