3

I have some library (actually the tbb library compiled with a different compiler), throwing an exception before main() proper started. Is there a way to catch that?

int main() { std::cout << "Hello World" << std::endl; }

gives

terminating with unexpected foreign exception
Abort (core dumped)

if I link against said library (which is not used in this example, but in other code it will be).

Walter
  • 44,150
  • 20
  • 113
  • 196
  • ...? How is this possible? – CinchBlue Feb 07 '17 at 12:07
  • Have you tried using a debugger? probably relevant [http://stackoverflow.com/questions/11289014/null-libcabi-dylib-terminate-called-throwing-an-exception](http://stackoverflow.com/questions/11289014/null-libcabi-dylib-terminate-called-throwing-an-exception) – bitcell Feb 07 '17 at 12:07
  • 2
    Which OS are you targetting? – Bathsheba Feb 07 '17 at 12:09
  • 3
    First of all it's not possible to catch an exception before `main` is called, unless you run in a debugger. Second of all catching such an exception would be pretty much useless, since your program would most likely not be able to continue anyway. Lastly, are you sure it's a C++ exception being thrown, and not an OS or hardware exception? Those are different things using the same terminology. – Some programmer dude Feb 07 '17 at 12:09
  • Are you willing to replace the standard startup files? C++ injects quite a lot of stuff before main, but you don't have to use the compilers version if you don't want to – Jon Chesterfield Feb 07 '17 at 12:10
  • 1
    @VermillionAzure Global variable with a constructor that throws an exception. – nwp Feb 07 '17 at 12:11
  • Have you tried `catch throw` in gdb ? – ks1322 Feb 07 '17 at 12:19
  • 1
    @Someprogrammerdude: `try catch` works within functions called before main. (it is just not possible to have a "global" `try cacth`). – Jarod42 Feb 07 '17 at 12:35
  • 5
    _"(compiled with a different compiler)"_ Don't do this – Lightness Races in Orbit Feb 07 '17 at 12:39
  • Take a look at [this](https://akrzemi1.wordpress.com/2011/10/05/using-stdterminate/), author proposes a specific use of `std::terminate` and `std::current_exception` to achieve a general `try...catch` and also a way to set handler for `std::terminate` before call of `main` (but you can't be sure registration of handler is done before any instantiation) – Garf365 Feb 07 '17 at 12:39
  • 2
    As mention by @LightnessRacesinOrbit using different compilers *may* be a reason. But it really depends on the "other" compiler. And the "current" compiler. None of which we know unfortunately. – Some programmer dude Feb 07 '17 at 12:43
  • 1
    Libraries with global statics with throwing constructors = evil – M.M Feb 07 '17 at 12:55
  • You can `throw` from anywhere in the program but `catch` must be right after `try`. You can't throw or catch in `global scope`. – Raindrop7 Feb 07 '17 at 13:02
  • @Someprogrammerdude Can you explain why you are saying that catching exceptions before `main` is not possible? You can execute functions (e.g. constructors) before `main` and have a perfectly valid stack. Is there something magic about `main`? – Emerald Weapon Feb 07 '17 at 13:28
  • 2
    If it's a shared library, you might be able to defer library load until after `main()` has started - either by not linking it and using explicit `dlopen()`, or by marking it as lazy-loaded in your linker flags. – Toby Speight Feb 07 '17 at 13:45
  • @EmeraldWeapon Yes it's possible to have global variables, or namespace variables, whose initialization calls functions where one can catch exceptions. But if you don't actually call the functions which throws the exception, then no it's not possible to catch it. And `main` *is* special as it's the function where everything really starts to run (global variable initialization aside). Without a `main` function you don't have a C++ *program*, just a collection of classes and functions really. – Some programmer dude Feb 07 '17 at 13:47

2 Answers2

3

Generally speaking, it is not possible in standard C++ to catch an exception that is thrown during construction of a global variable (which is outside scope of any function).

I believe the closest possibility is to use a function-try-block for the body of the constructor of the static.

 class MyStatics
 {
      public:

          MyStatics();

      private:

          X x;    // construction may fail
          Y y;    // construction may fail
            // etc
 };

 static MyStatics all_my_statics;

 MyStatics::Mystatics() : x(), y()   // implement using a function try block
 try
 {
     if (some_condition) throw some_exception();   // construction may even fail here
 }
 catch (SomeException &)
 {
     // handler for SomeException
 }

If an exception is thrown during construction of all_my_statics, then any fully-constructed members of it will be destructed (i.e. MyStatics members do not exist within such a catch block).

Within the catch block there aren't many options, after reporting about the caught exceptions. The main options will be;

  • throw (or rethrow) an exception (since the construction of MyStatics has failed). That exception will cause std::terminate() to be called.
  • terminate the program in some other way deemed to be "cleaner".

It is not a good idea to swallow an exception thrown during construction of a static since the program (e.g. within main()) will have no indication that statics it relies on have not been properly constructed.

It is more usual to place the static object within a function

  X &the_x()
  try
  {
       static X thing;
       return thing; 
  }
  catch (Whatever &)
  {
       // handler
  }

Bear in mind that every call of the_x() will attempt to construct thing until one of them succeeds (i.e. if an exception is thrown the first time, the second call will attempt to construct thing, etc). However, if the first call of the_x() within the program can be identified and exceptions from it caught (i.e. wrap it in a try/catch) it is not necessary to catch exceptions from subsequent calls - since, if the first call doesn't throw, the construction of thing has succeeded, and it will not be constructed again.

Peter
  • 35,646
  • 4
  • 32
  • 74
2

I found this interesting source. It bases his construction on std::terminate functionality

He proposes to use a sort of global try...catch (you can't continue anymore to run, but you can act depending of exception):

[[noreturn]] void onTerminate() noexcept
{
    if( auto exc = std::current_exception() ) { 
        // we have an exception
        try{
            rethrow_exception( exc ); // throw to recognize the type
        }
        catch( MyException const& exc ) {
            // additional action
        }
        catch( MyOtherException const& exc ) {
            // additional action
        }
        catch( std::exception const& exc ) {
            // additional action
        }
       catch( ... ) {
            // additional action
        }
    }

    std::_Exit( EXIT_FAILURE );
}

and to register this caller when an exception occurred, earliest possible:

const auto installed{ std::set_terminate(&handler) };

int main() {
    // run...
}

But you have to know that you can't be sure that std::set_terminate will be called before any instanciation.

Garf365
  • 3,619
  • 5
  • 29
  • 41
  • Not quite a "global try...catch". More like a catch inside terminate (you can still never continue execution). – rustyx Feb 07 '17 at 13:26