I've got some Linux code I'm trying to reuse in Windows. I'm using the compiler and make that were installed with Qt 5.9.1 and I'm using googletest for unit testing. What tested fine under Linux is aborting under Windows. (See What is the cause of "This application has requested the Runtime to terminate it in an unusual way"? for how I know it is aborting.)
Tool version info:
- googletest
- Git label "release-1.8.0"
- cmake
- 3.9.1
- i686-w64-mingw32-g++
- (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 5.3.0
- mingw32-make
- GNU Make 4.1, Built for i686-w64-mingw32
Simplified code that will generate the error:
-- MyClass.h
#pragma once
class MyClass
{
public:
MyClass();
~MyClass();
void Func();
};
-- MyClass.cpp
/*01*/ #include "MyClass.h"
/*02*/
/*03*/ #include <sstream>
/*04*/ #include <stdexcept>
/*05*/
/*06*/ namespace {
/*07*/ std::stringstream ss;
/*08*/ }
/*09*/
/*10*/ MyClass::MyClass() {}
/*11*/ MyClass::~MyClass() {}
/*12*/
/*13*/ void MyClass::Func() {
/*14*/ std::stringstream ss;
/*15*/ ss << "BOO!";
/*16*/ throw std::runtime_error( ss.str() );
/*17*/ //throw std::runtime_error( std::string( ss.str().c_str() ) );
/*18*/ //throw std::runtime_error( "BOO!" );
/*19*/ }
-- MyClassTestSuite.cpp
#include <gtest/gtest.h>
#include <MyClass.h>
#include <stdexcept>
#include <iostream>
class MyClassTestSuite: public ::testing::Test
{
};
TEST_F( MyClassTestSuite, test_FuncThrows )
{
MyClass obj;
try
{
obj.Func();
FAIL();
}
catch( std::runtime_error & e ) {}
}
The error I get is:
This application has requested the Runtime to terminate it in an unusual way.
Regarding the commented out code in MyClass.cpp:
- Replacing line 16 with line 17 still produces the error.
- Replacing lines 14-17 with line 18 does not produce an error.
- Commenting out line 14 to allow the anonymous namespace
ss
to be the in-scope variable for exception creation does not produce an error.
--- Update ------
When I create a main and run this outside the scope of using cmake then:
main.cpp:
#include "MyClass.h"
#include <stdexcept>
#include <iostream>
int main( int, char** )
{
MyClass obj;
std::cout << "Calling\n";
try
{
obj.Func();
std::cout << "Call successful\n";
}
catch( const std::runtime_error & e )
{
std::cout << "Caught exception " << e.what() << "\n";
}
return 0;
}
output:
C:\> i686-w64-mingw32-g++.exe MyClass.cpp main.cpp -o test.exe
C:\> test.exe
Calling
Caught exception BOO!
So the exception was correctly thrown and caught.
I've run ldd, and the answer ldd gives is that both the stand-alone main that works and the unittest exe that doesn't work both have the exact same dependency chain.
This post suggests that there could be some Microsoft rewrite of something that is the culprit. (One of many straws to grasp at.)
-- Oddities ------
- In the same project is a module that does this exact same thing but has no issues. The main difference is that this module's function does something useful and then decides whether or not to throw; versus
MyClass::Func()
which only throws. - My unsimplified code derives from a base class. If I make
ss
a protected member of the base class, the derived class functions as expected (without error) but throwing from the base class causes an abort. - I've another library that I'm porting (since this was originally posted) and for that library there was one googletest test suite that would not work correctly until I disabled the
-O3
optimization switch. I have tried the same with this library but it has no effect.
This is starting to feel like a bug in the compiler, but how would I prove that? (And my expectation is that in trying to prove it I'd find the root cause and it wouldn't be the compiler. Compilers are not thrown "into the wild" willy-nilly.) This bug really feels like the variables are being referenced after their memory has been released.
-- Likely culprit ------
After reading about the differences between SJLJ, SEH, and DW2 I learned that there are different exception types (who knew? Not me, until 5 minutes ago) and SEH is what Windows likes, especially on 64-bit machines. I suspect this is my issue, though I've not proven it. My tool chain dev process has led me down a path that this should be a non-issue now, but it is a feather in my hat so the next time I run into this issue I'll know where to check. And knowing is half the battle ...