Thursday, 5 July 2012

MinGW C++11 Chrono Library Bug

I've had a rollercoaster of a day, I was awake most of the night in agony, left off work (after calling the boss - or rather the wife did) and I went to see my GP, who put me on some really strong drugs to calm my bones, seems my heel bones are really not getting on with the rest of my body... Wierd...

Anyway, when we got back from this GP visit, I sat down to expand my mind a little in the direction of C++, I was specifically going down a check list of some work items I needed to optimise, and one of the things I was looking at was timing in the systems... I wanted to build on the very fast file system library I've written in C++ for use in C# with a library to very quickly handle times.  Not that the C# support for times is not good, but its not very useful for some of the more precise measurements I wanted to take.

So, after a bit of reading about POSIX time, and Windows API time, not to mention looking at Boost::chrono I started to check out if there were any additions to time handling in C++11, an obvious place to look, but strangely the last I went to.  Anyway, seems much of the boost::chrono library has been accepted as standard in C++ STL, and I quickly set about reading what I wanted...

My next problem was getting this all to work in some compiler, I tried out a bunch of things in g++ on the laptop and was happy enough under Ubuntu.  But I need this for work, that means Windows...

Introducing MinGW... I grabbed the latest get-install executable and set about installing it, then started to throw together some code, my first test program was to simply output the epoch, now, min and max time_points for the system clock, this is a standard bit of demo code, and I lift it straight from:

Click me to visit Amazon and buy this fab book.

Page 152 if you're interested... Anyway, I typed the code in and here is how it looks:


#include <string>
#include <iostream>
#include <chrono>
#include <ctime>

using namespace std;
using namespace std::chrono;

const string asString (const system_clock::time_point& p_TimePoint)
{
string l_timeString ("");
try
{
time_t l_time = system_clock::to_time_t(p_TimePoint);
l_timeString = ctime(&l_time);
if ( l_timeString.size() > 0 )
{
l_timeString.resize(l_timeString.size()-1);
}
}
catch (exception& l_ex)
{
cout << "Ex: " << l_ex.what() << endl;
}
return l_timeString;
}

void shoo ()
{
try
{
system_clock::time_point l_tp;
cout << "Epoch: " << asString(l_tp) << endl;

l_tp = system_clock::now();
cout << "Now: " << asString(l_tp) << endl;

l_tp = system_clock::time_point::min();
cout << "Min: " << asString(l_tp) << endl;
l_tp = system_clock::time_point::max();
cout << "Max: " << asString(l_tp) << endl;
}
catch (exception& l_ex)
{
cout << "Ex: " << l_ex.what() << endl;
}
}

int main ()
{
shoo();
cout << "Done, press ENTER" << endl;
cin.get();
return 0;
}

Next I set about compiling under windows...so with the code above saved as "C:\Code\Test.cpp" I get a command prompt and did this:

path=%path%;c:\MinGW\bin
cd \Code
g++ -x c++ -Wall -std=c++11 Test.cpp -o Test.exe

I know I need to copy a couple of dll's from the MinGW bin folder (libgcc_s_dw2-1.dll & libstdc++-6.dll) before I can run the application.  With them copied over I run the app... And... I get a crash...


I'm not using a debugger at the mo, just trying out this little bit of example code, so I'm unable to delve too deeply into what's going on... However, after a little trial and error from the four system clock calls I know its got to be one of them, and just narrowing it down I find out that using the generated "system_clock::time_point::min();" is throwing the spanner in the works.

The other calls all work when being passed through my code, just the minimum time_point does not?!?!?!

Checking around the internet, I find no-one else mentioning this, I see the use of the minimum time point a lot, and I see it in a lot of examples... But this crashes...

//l_tp = system_clock::time_point::min();
//cout << "Min: " << asString(l_tp) << endl;

Rem these two lines out, and rebuild... All works fine!


So, am I able to generate a min time point?...

auto l_tp = system_clock::time_point::min();


Yep, this works... so, this leaves my passing it to asString...

The only real call of any logical significance in there is "system_clock_to_time_t"... voila, that's the problem, passing the time_point min to that function results in a logic error exception... but why?... That value should be output easily enough, and represented as a time_t... all the references I have say it is so...

So guys and gals, passing your time_point::min to system_clock::to_time_t will crash on MinGW output applications running their current, as of the time of writing, C++11 libraries... :(

2 comments:

  1. Lol, I've just found this problem too, and from exactly the same source. Copying the 'chrono1.cpp' code from the Josuttis book gives me the same errors. And only six years have passed since you found it! :-D

    ReplyDelete
    Replies
    1. Nice to know I was not alone in the dark here.

      Delete