0

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 ...

PfunnyGuy
  • 750
  • 9
  • 22
  • Apart from anything else (like what do those macros do?) this `catch ( std::runtime_error & e ) ` should be `catch ( const std::runtime_error & e ) ` –  Oct 27 '17 at 15:47
  • If you are going to post code you expect us to read and help you with, don't use macros or at least include their full definition(s). – Richard Critten Oct 27 '17 at 15:48
  • These are well-known macros if you use gtest, and I don't see anything suspicious there. What version of the compiler and C++ runtime are you using? Can you make it fail with Visual Studio's compiler or clang? Can you make a minimum compilable sample that demonstrates the problem? I don't see anything obviously wrong with your code. `std::runtime_error` will copy the string passed into it, so the fact that it's a temporary should not be an issue. – metal Oct 27 '17 at 15:56
  • @metal - I'll work on getting a minimal compilation file set and posting it. And thank you for noting that those are standard gtest macros. – PfunnyGuy Oct 27 '17 at 16:30

0 Answers0