29

I was once advised that a C++ program should ultimately catch all exceptions. The reasoning given at the time was essentially that programs which allow exceptions to bubble up outside of main() enter a weird zombie state. I was told this several years ago and in retrospect I believe the observed phenomenon was due to lengthy generation of exceptionally large core dumps from the project in question.

At the time this seemed bizarre but convincing. It was totally nonsensical that C++ should "punish" programmers for not catching all exceptions but the evidence before me did seem to back this up. For the project in question, programs that threw uncaught exceptions did seem to enter a weird zombie state -- or as I suspect the cause was now, a process in the midst of an unwanted core dump is unusually hard to stop.

(For anyone wondering why this wasn't more obvious at the time: The project generated a large amount of output in multiple files from multiple processes which effectively obscured any sort of aborted (core dumped) message and in this particular case, post-mortem examination of core dumps wasn't an important debugging technique so core dumps weren't given much thought. Issues with a program usually didn't depend on state accumulated from many events over time by a long lived program but rather the initial inputs to a short lived program (<1 hour) so it was more practical to just rerun a program with the same inputs from a debug build or in a debugger to get more info.)

Currently, I'm unsure of whether there is any major advantage or disadvantage of catching exceptions solely for the purpose of preventing exceptions from leaving main().

The small advantage I can think of for allowing exceptions to bubble up past main() is that it causes the result of std::exception::what() to be printed to the terminal (at least with gcc compiled programs on Linux). On the other hand, this is trivial to achieve by instead catching all exceptions derived from std::exception and printing the result of std::exception::what() and if it's desirable to print a message from an exception that doesn't derive from std::exception then it must be caught before leaving main() in order to print the message.

The modest disadvantage I can think of for allowing exceptions to bubble up past main() is that unwanted core dumps may be generated. For a process using a large amount of memory this can be quite a nuisance and controlling core dumping behavior from a program requires OS-specific function calls. On the other hand, if a core dump and exit is desired then this could instead be achieved at any time by calling std::abort() and an exit without core dump can be achieved at any time by calling std::exit().

Anecdotally, I don't think I've ever seen the default what(): ... message printed by a widely distributed program upon crashing.

What, if any, are the strong arguments for or against allowing C++ exceptions to bubble up past main()?

Edit: There are a lot of general exception handling questions on this site. My question is specifically about C++ exceptions that cannot be handled and have made it all the way to main() -- maybe an error message can be printed but it's an immediately show stopping error.

6

7 Answers 7

25

One problem with letting exceptions go past main is that the program will end with a call to std::terminate which default behavior is to call std::abort. It is only implementation defined if stack unwinding is done before calling terminate so your program can end without calling a single destructor! If you have some resource that really needed to be restored by a destructor call, you're in a pickle...

7
  • 12
    If you have some resource that really needed to be restored by a destructor call, you're in a pickle... => Given that (unfortunately) C++ is quite crash-prone, and that's without mentioning that the OS might decide to kill your program at any time (OOM killer in Unix for example), your program (and its environment) need be tailored to support crashes. Commented Jan 30, 2016 at 13:46
  • 6
    @Praxeolitic: I am saying that not all crashes unwind the stack, for example std::abort does not and thus failed assertions don't either. It's also worthwhile to note that on modern OSes, the OS itself will cleanup a lot of resources (memory, file handles, ...) which are tied to the process ID. Finally, I was also hinting at "Defense in Depth": it's unreliable to expect that all other processes are bug-proof and will always release the resources they acquired (sessions, nicely finish writing files, ...) you have to plan for it... Commented Jan 30, 2016 at 14:45
  • 1
    @immibis Huh? My software needs to cleanly shutdown during a power failure now? That's going to be tricky... at least until SIGPOWEROUTAGE gets implemented... Commented Jan 31, 2016 at 9:00
  • 3
    @Praxeolitic No, your software needs to not corrupt data during a power failure. And if you can manage that, you can also manage to not corrupt data after an unhandled exception.
    – user20574
    Commented Jan 31, 2016 at 9:55
  • 1
    @Praxeolitic: Actually, this does exist. You'll want to listen for the WM_POWERBROADCAST message. This only works if your computer is battery-powered (if you're using a laptop or a UPS).
    – Brian
    Commented Feb 5, 2016 at 15:35
29

The main reason for not letting exceptions escape from main is because otherwise you lose all possibility to control how the problem gets reported to your users.

For a program that is not intended to be used a long time or distributed widely, it can be acceptable that unexpected errors are reported in whatever way the OS decides to do it (for example, showing an in-your-face error dialog on Windows).

For programs that you sell, or that are provided to the general public by an organization that has a reputation to uphold, it is generally a better idea to report in a nice way that you encountered an unexpected problem and try to save as much of the user's data as possible. Not losing half a day's work of your user and not crashing unexpectedly, but shutting down semi-gracefully is generally much better for your business reputation than the alternative.

4
  • Are you sure the default behavior of a C++ exception that leaves main() has much to do with the OS? The OS might know nothing of C++. My guess was that it's determined by code the compiler inserts somewhere into the program. Commented Jan 30, 2016 at 9:53
  • 5
    @Praxeolitic: It is more that the OS sets conventions and the compiler generates code to fulfill those conventions when a program terminates unexpectedly. The bottom-line is that unexpected program termination should be avoided whenever reasonably possible. Commented Jan 30, 2016 at 9:59
  • You only loose control within the scope of std C++. An implementation specific way to handle such "crashes" should be available. C++ doen't usually run in a vacuum.
    – Martin Ba
    Commented Jan 31, 2016 at 8:20
  • That in-your-face error dialog can be configured on/off in the registry for what that's worth -- but you would need control of the registry to do this -- and most programs aren't running in kiosk mode (having taken over the OS).
    – PerryC
    Commented Feb 5, 2016 at 0:15
11

TL;DR: What does the specification say?


A technical detour...

When an exception is thrown and no handler is ready for it:

  • it is implementation defined whether the stack is unwound or not
  • std::terminate is called, which by default aborts
  • depending on your environment setup, aborting may or may not leave a crash report behind

The latter can be useful for very infrequent bugs (because reproducing them is a time-wasting process).


Whether to catch all exceptions or not is, ultimately, a matter of specification:

  • is it specified how to report user errors? (invalid value, ...)
  • is it specified how to report functional errors? (missing target directory, ...)
  • is it specified how to report technical errors? (assertion firing up, ...)

For any production program, this should be specified, and you should follow the specification (and maybe argue that it be changed).

For quickly thrown together programs to be used only by technical people (you, your teammates), either is fine. I recommend letting it crash and setup the environment to get a report or not depending on your needs.

1
  • 1
    This. The deciding factors wrt. Are basically outside the scope of C++.
    – Martin Ba
    Commented Jan 31, 2016 at 8:21
4

An exception that you catch gives you the opportunity to print a nice error message or even try to recover from the error (possibly by just re-launching the application).

However, in C++ an exception doesn't hold information about the program state when it was thrown. If you catch it, all such state is forgotten, whereas if you let the program crash, the state is usually still there and can be read from the program dump, making it easier to debug.

So it's a trade-off.

4

The moment you know you have to abort, go ahead and call std::terminate already to curtail any further damage.

If you know you can wind down safely, do that instead. Remember that stack-unwinding is not guaranteed when an exception is never caught, so catch and rethrow.

If you can safely report/log the error better than the system will do it on its own, go ahead.
But be really sure not to inadvertently make matters worse while doing so.

It's often too late to save data when you detect an irrecoverable error, though it depends on the specific error.
Anyway, if your program is written for fast recovery, just killing it might be the best way to end it even if it's just a normal shutdown.

1

Crashing gracefully is a good thing most of the time -- but there are trade-offs. Sometimes it's a good thing to crash. I should mention that I'm mostly thinking about debugging in the very large. For a simple program -- although this might still be useful, it's nowhere near as helpful as it is with a very complex program (or several complex programs interacting).

You don't want to crash in public (although this is really unavoidable -- programs crash, and a truly mathematically verifiable non-crashing program is not what we're talking about here). Think of Bill Gates BSODing in the middle of a demo -- bad, right? Nonetheless, we can try to figure out why we crashed and not crash again in the same way.

I turned on a feature of Windows Error Reporting that creates local crash dumps on unhandled exceptions. It works wonders if you have the symbol files associated with your (crashing) build. Interestingly enough, because I set up this tool, I want to crash more -- because I learn from each crash. Then I can fix the bugs and crash less.

So for now, I want my programs to throw all the way to the top and crash. In the future, I might want to gracefully eat all my exceptions -- but not if I can make them work for me.

You can read more about Local Crash Dumps here if you're interested: Collecting User-Mode Dumps

-6

Ultimately, if an exception bubbles up past main(), it is going to crash your application, and in my mind an app should never never crash. If it is ok to crash an app in one place, then why not anywhere? Why bother with exception handling at all? (Sarcasm, not really suggesting this...)

You might have a global try/catch that prints an elegant message telling the user that an unrecoverable error has occurred and that they need to email bob in IT about it or something similar, but crashing is completely unprofessional and unacceptable. Its trivial to prevent and you can inform a user about what just happened and how to fix things so it doesn't happen again.

Crashing is strictly amateur hour.

5
  • 8
    So, better pretend everything is working right and overwrite all the permanent storage with gibberish instead? Commented Jan 30, 2016 at 10:49
  • 1
    @Deduplicator: No: you can always catch the exception and handle it.
    – Giorgio
    Commented Jan 30, 2016 at 12:45
  • 5
    If you know how to handle it, you will probably handle it long before you get up to main. If you don't know how to handle it, pretending you do is obviously a really horrible bug. Commented Jan 30, 2016 at 12:52
  • 8
    but crashing is completely unprofessional and unacceptable => spending time working on useless features is unprofessional: crashing only matters if it matters to the end user, if it does not, then letting it crash (and getting a crash report, with a memory dump) is more economical. Commented Jan 30, 2016 at 13:44
  • Matthieu M. if it really takes you that much effort to log an error, save any open files, and paint a friendly message on the screen, I don't know what to say. If you think that it is useless to gracefully fail, you probably should go talk to whoever is doing tech support for your code.
    – Roger Hill
    Commented Feb 3, 2016 at 18:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.