I have a test program, based on CPPUNIT library and Qt that runs ~900 unit tests. This program is deployed on Android using QtCreator. It links with ~80 libraries, each one defining some tests.
After a code change, test program started crashing due to std::bad_cast
being thrown.
Original code (no bad_cast):
class TimeUnit
{
friend std::ostream& operator<<(std::ostream &os, const TimeUnit& var);
public:
std::string TimeUnit::toString() const
{
std::stringstream stream;
static std::string facetStr = "%Y/%m/%d %H:%M";
stream.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_facet(facetStr.c_str())));
stream << *m_time;
return stream.str();
}
private:
boost::posix_time::ptime m_time;
};
std::ostream& operator<<(std::ostream &os, const TimeUnit& var)
{
os << var.toString();
return os;
}
New code (makes the test program throw bad_cast at some point):
class TimeUnit
{
friend std::ostream& operator<<(std::ostream &os, const TimeUnit& var);
public:
std::string TimeUnit::toString() const
{
std::stringstream stream;
stream << *this;
return stream.str();
}
private:
boost::posix_time::ptime m_time;
};
std::ostream& operator<<(std::ostream &os, const TimeUnit& var)
{
static std::string facetStr = "%Y/%m/%d %H:%M";
os.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_facet(facetStr.c_str())));
// this next line ends up throwing std::bad_cast!
os << *(var.m_time);
return os;
}
The new code makes std::bad_cast
exception be thrown by my operator<<
at some point. According to the doc:
An exception of this type is thrown when a dynamic_cast to a reference type fails the run-time check (e.g. because the types are not related by inheritance), and also from std::use_facet if the requested facet does not exist in the locale.
...boost operator<<
for boost::posix_time::ptime
does a use_facet
...
After a lot of investigation, I can conclude that:
- The crash is Android-specific (Window works just prefectly)
- It is due to attaching a facet to
std::cout
(in the new code, if I create a localstd::stringstream
apply the facet to it and later copy the result withos << str.str()
, no more crash) os.imbue(std::locale(std::locale::classic(),...)
oros.imbue(std::locale(os.getloc(),...))
both will lead to the same crash- Removing
os.imbue
call makes the crash disappear - Calling
os.imbue(std::locale::classic());
before returning from myoperator<<
does not fix the issue
Unfortunately, I tried to isolate the problem in a MCVE but could not reproduce the problem with some more basic code...
So my question is (are):
- Am I doing something wrong in my
operator<<
? - Why would this code work on Windows and crash on Android? Could this be due to an insane C++ runtime that would delete the facet in a wrong way?
Edit:
After some more investigation, I found out that the bad_cast
is only thrown if I redirect std::cout
to a file from my main, using:
class ScopedRedirect
{
public:
ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
mOriginal(inOriginal),
mOldBuffer(inOriginal.rdbuf(inRedirect.rdbuf()))
{}
virtual ~ScopedRedirect()
{
mOriginal.rdbuf(mOldBuffer);
}
ScopedRedirect(const ScopedRedirect&) = delete;
ScopedRedirect& operator=(const ScopedRedirect&) = delete;
protected:
std::ostream & mOriginal;
std::streambuf * mOldBuffer;
};
int main( int argc, char* argv[] )
{
std::fstream output( "cout.txt", std::ios_base::out );
assert( output.is_open() );
ScopedRedirect redirectCount( std::cout, output );
...
}