Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::chrono::duration_cast - is GCC implementation bugged?

Tags:

c++

std

gcc

chrono

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?

like image 520
Valeriop84 Avatar asked Jan 22 '18 08:01

Valeriop84


1 Answers

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.

like image 185
Massimiliano Janes Avatar answered Nov 06 '22 13:11

Massimiliano Janes