Fix a UB in chrono

This commit is contained in:
Victor Zverovich 2022-01-09 10:22:36 -08:00
parent c06bef7273
commit d9f045fba1
2 changed files with 20 additions and 3 deletions

View File

@ -1663,7 +1663,7 @@ struct chrono_formatter {
out = format_decimal<char_type>(out, n, num_digits).end; out = format_decimal<char_type>(out, n, num_digits).end;
} }
template <class Duration> void write_fractional_seconds(Duration d) { template <typename Duration> void write_fractional_seconds(Duration d) {
constexpr auto num_fractional_digits = constexpr auto num_fractional_digits =
count_fractional_digits(Duration::period::num, Duration::period::den); count_fractional_digits(Duration::period::num, Duration::period::den);
@ -1770,8 +1770,22 @@ struct chrono_formatter {
if (handle_nan_inf()) return; if (handle_nan_inf()) return;
if (ns == numeric_system::standard) { if (ns == numeric_system::standard) {
write(second(), 2); if (std::is_floating_point<rep>::value) {
write_fractional_seconds(std::chrono::duration<rep, Period>{val}); 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<rep>(Period::num) /
static_cast<rep>(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<rep, Period>(val));
}
return; return;
} }
auto time = tm(); auto time = tm();

View File

@ -557,6 +557,9 @@ TEST(chrono_test, special_durations) {
"03:33"); "03:33");
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}), EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
"03:33:20"); "03:33:20");
EXPECT_EQ("44.000000000000",
fmt::format("{:%S}", std::chrono::duration<float, std::pico>(
1.54213895E+26)));
} }
TEST(chrono_test, unsigned_duration) { TEST(chrono_test, unsigned_duration) {