Reputation: 125
I think i've found a bug in GCC implementation of std::chrono::duration_cast. Could anyone please confirm me this?
Test code:
using Ticks = std::chrono::duration<long long, std::ratio_multiply<std::chrono::nanoseconds::period, std::ratio<100>>>;
using dur = typename std::chrono::system_clock::duration;
int main()
{
std::chrono::time_point<std::chrono::system_clock> earliest {std::chrono::duration_cast<dur>(
std::chrono::time_point<std::chrono::system_clock, Ticks>::max().time_since_epoch())};
auto ticks = std::chrono::time_point<std::chrono::system_clock, Ticks>::max().time_since_epoch().count();
std::cout << "Ticks: " << ticks << "\n";
std::cout << sizeof(earliest.time_since_epoch().count()) << "\n";
std::cout << "Microseconds: " << earliest.time_since_epoch().count() << "\n";
std::time_t t = std::chrono::system_clock::to_time_t(earliest);
std::cout << "earliest:\n" << std::ctime(&t);
}
Output with clang 3.8 is:
Ticks: 9223372036854775807
8
Microseconds: 922337203685477580
earliest:
Sun Sep 14 02:48:05 31197
Output with GCC 7.1 is:
Ticks: 9223372036854775807
8
Microseconds: -100
earliest:
Thu Jan 1 00:00:00 1970
Am i wrong?
Upvotes: 6
Views: 770
Reputation: 5624
It's not a bug, you're just causing a signed overflow, hence undefined behaviour. Indeed, your code is relying on platform dependent assumptions (the system clock period and rep type) that just happens to fail in the gcc test case.
At the moment of writing, the system_clock
used by Coliru's GCC environment has a nanosecond duration period of long type, that in turn have the same size of long long.
So, when you duration_cast<system_clock::duration>
a time_point<system_clock,Ticks>::max().time_since_epoch()
you are casting a duration of numeric_limits<Ticks::rep>::max()
periods of 100 nanoseconds each into a nanosecond duration of long type, resulting in something equivalent to numeric_limits<Ticks::rep>::max()*100
that clearly overflows (your two-complement signed implementation happens to wrap, resulting in -100
; anyway, this is still undefined behaviour).
Conversely, on my clang copy, system_clock
has a microsecond duration period of long long type, resulting in a duration cast equivalent ot numeric_limits<Ticks::rep>::max()/10
.
Upvotes: 5