C++ catching all exceptions
Asked Answered
V

16

336

Is there a c++ equivalent of Java's

try {
    ...
}
catch (Throwable t) {
    ...
}

I am trying to debug Java/jni code that calls native windows functions and the virtual machine keeps crashing. The native code appears fine in unit testing and only seems to crash when called through jni. A generic exception catching mechanism would prove extremely useful.

Venus answered 25/11, 2008 at 0:11 Comment(3)
Same as How to build a C++ Dll wrapper that catches all exceptions?Peptize
Note that most crashes are not caused by exceptions in C++. You can catch all exceptions, but that won't prevent many crashes.Gallfly
What you may be looking for if you ended up here: https://mcmap.net/q/21342/-segmentation-fault-handling man7.org/linux/man-pages/man2/sigaction.2.html man7.org/linux/man-pages/man7/signal.7.htmlHeshvan
N
406
try{
    // ...
} catch (...) {
    // ...
}

will catch all C++ exceptions, but it should be considered bad design. You can use c++11's new std::current_exception mechanism, but if you don't have the ability to use c++11 (legacy code systems requiring a rewrite), then you have no named exception pointer to use to get a message or name. You may want to add separate catch clauses for the various exceptions you can catch, and only catch everything at the bottom to record an unexpected exception. E.g.:

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}
Namedropping answered 25/11, 2008 at 0:22 Comment(15)
It is a good practice to catch exceptions by const reference. As in: catch(std::exception const & ex) { /* ... */ }Oversubscribe
@coryan, Thanks for the reminder. I've been spending too much time in C# land lately. :)Namedropping
@coryan: Why is it good practice to catch by const reference?Sniper
Avoiding unnecessary copies is one benefit.Namedropping
-1: the suggestion that this will "catch all exceptions in C++" is misleading. Try generating a divide by zero error inside the try block. You will see that it will generate an exception that is not caught, yet the code is clearly in C++. It would be more helpful to state that this will "catch all C++ exceptions" and then add some mention of structured exceptions to the notes on limited usefulness.Tactful
@omatai: Fixed, it will catch all C++ exceptions. Division by zero is undefined behavior and does not generate a C++ exception.Gallfly
@Tactful It may seem misleading, but it is still accurate. Dividing by zero raises a signal; it does not throw an exception. The two are different, and the language has terminology for both.Deterrence
But you can use the Windows __try {} __except() to catch all exceptions, even hardware signals that would normally crash your application. Check msdn.microsoft.com/en-us/library/s58ftw19.aspx and msdn.microsoft.com/en-us/library/ms681409(v=vs.85).aspxShyster
Ah, but this was a question about C++, not about platform-specific extensions.Namedropping
When using the ... syntax, how do I get a reference to the thing I caught so I can print it or read its fields or learn its type? What type could the caught thing have, if not std::exception or std::string? Which other types are throwable in c++?Marucci
@dinosaur: The answer covers your question. If you're using an older flavor of C++, you get no reference to the thrown object (which, btw, could be of any type. C++ does not limit throwable types: isocpp.org/wiki/faq/exceptions#what-to-throw). If you're using a newer flavor of C++, you might be able to leverage current_exception: cplusplus.com/reference/exception/current_exception .Namedropping
@TimMB Another major benefit is that it doesn't cause your exception object to be sliced, so that virtual functions like what() actually work.Metrical
@Marucci the reason to nest the catch blocks like this is to get a workable type for the exception object. C++ requires variable types to be known at compile time, and there's no uber-class that can be used as the parent type for every exception; std::exception is the closest but as you can see it isn't universal. The biggest problem I've seen is with Microsoft's MFC library, which supported exceptions before std::exception was part of the language, so it throws a pointer to class CException.Almatadema
Is it ok to to catch (...) if you do throw;?Mccaleb
@Mccaleb I was surprised to find out it does not catch in this case.Akins
A
182

Someone should add that one cannot catch "crashes" in C++ code. Those don't throw exceptions, but do anything they like. When you see a program crashing because of say a null-pointer dereference, it's doing undefined behavior. There is no std::null_pointer_exception. Trying to catch exceptions won't help there.

Just for the case someone is reading this thread and thinks he can get the cause of the program crashes. A Debugger like gdb should be used instead.

Abstractionism answered 25/11, 2008 at 1:7 Comment(8)
Well, as Shy points out, it is possible with the VC compiler. It's not a good idea, but it is possible.Charleencharlemagne
yeah with SEH. but not with sane standard c++ techniques :) well if you stick to windows you can nearly do everything :)Abstractionism
Mmm... thanks for this tidbit. I've been looking for the answer as to why my null-pointer exceptions aren't beeing caught!Unteach
You can catch segfaults with SEH on Windows and signal(2)/sigaction(2) on POSIX systems, which covers that vast majority of systems in use today, but like exception handling, it's not something that should be used for normal flow control. It's more of a "do something useful before dying."Intelligentsia
@AdamRosenfield until you have implemented try { .. } catch(...) { ... } for catching using signal/sigaction, i wouldn't call it "catching" :) If in a signal handler, it's relatively hard for the programmer to know where in the code the crash happened (i'm talking about programmatically detecting that), compared to try/catch.Abstractionism
One can use _set_se_translator to catch structured exceptions on Windows as C++ exceptions. This includes read/write access violation, stack overflow and division by zero.Whoso
what is difference between catch(...) vs catch(std::exception)?Green
That's correct, but sometimes we can catch a sigabort which also causes a crash if we do not take an immediate action like a graceful termination.Dehorn
R
110

This is how you can reverse-engineer the exception type from within catch(...) should you need to (may be useful when catching unknown from a third party library) with GCC:

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

and if you can afford using Boost you can make your catch section even simpler (on the outside) and potentially cross-platform

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}
Raama answered 10/6, 2014 at 13:19 Comment(8)
what is difference between catch(...) vs catch(std::exception)?Green
In C++ you can throw anything, an int for instance. ... would catch that too. You “should” catch exceptions by const&, btw.Raama
FYI, in vs2015, "boost::current_exception_diagnostic_information()" just returns "No diagnostic information available." even with debug information available.Friedcake
I'm pretty sure that p.__cxa_exception_type()->name() isn't going to be portable. In fact, I just tried it with clang and it wouldn't compile.Evangelinaevangeline
@EdwardFalk - the first sentence of the answer explicitly says "GCC", so - dahRaama
When using catch (...), the body of the catch should either do throw; to re-throw the exception after e.g. logging it, or terminate the program altogether (e.g. std::terminate()). Unless one knows how to handle an exception, one should not attempt to "handle" it. For example, on some implementations trying to kill a thread causes an exception (that is not a subclass of std::exception) to be thrown in that thread so that the thread's stack gets unwinded before stopping the thread. So we shouldn't "catch all exceptions unconditionally" since there may be suprising cases.Coyne
@Coyne - it depends. Inside main(), like in my example it is a legit thing to do, because you might want to log and exit, or you might want to abort and dump the core, or whatever, depends on how you operate your software.Raama
@Raama Yes, you're right; that pretty much what I meant too! We should only handle errors when we know what to do with them. We should just recognize that catch(...) may catch stuff that we don't want to catch. IMO, the bottom line is: in the majority of cases, we should re-throw or terminate the program inside catch(...) after e.g. logging. But yes, in a few cases, if we really, really know what to do because we've read the compiler's documentation and the standard and we know what's right for our application, then we should do that of course!Coyne
U
76
try {
   // ...
} catch (...) {
   // ...
}

Note that the ... inside the catch is a real ellipsis, ie. three dots.

However, because C++ exceptions are not necessarily subclasses of a base Exception class, there isn't any way to actually see the exception variable that is thrown when using this construct.

Uralic answered 25/11, 2008 at 0:15 Comment(5)
In C++11 there is: try { std::string().at(1); // this generates an std::out_of_range } catch(...) { eptr = std::current_exception(); // capture }Magnetohydrodynamics
@bfontaine: Well yes, but I said that to distinguish the catch specifier from the existing code placeholder in a comment (// ...) which obviously isn't C++ syntax.Uralic
@GregHewgill: yes, it was just typographic nitpicking.Boarder
@bfontaine: Fair enough. :)Uralic
So you mean we cannot log some kind of e.what() on exceptions caught within (...). Right?Dehorn
H
60

it is not possible (in C++) to catch all exceptions in a portable manner. This is because some exceptions are not exceptions in a C++ context. This includes things like division by zero errors and others. It is possible to hack about and thus get the ability to throw exceptions when these errors happen, but it's not easy to do and certainly not easy to get right in a portable manner.

If you want to catch all STL exceptions, you can do

try { ... } catch( const std::exception &e) { ... }

Which will allow you do use e.what(), which will return a const char*, which can tell you more about the exception itself. This is the construct that resembles the Java construct, you asked about, the most.

This will not help you if someone is stupid enough to throw an exception that does not inherit from std::exception.

Habitat answered 11/10, 2009 at 15:57 Comment(1)
Divide by zero is undefined behaviour, and undefined behaviour is not exceptional behaviour (in any language). If your code has undefined behaviour then your entire program is invalid -- in the same way that a null reference invalidates a C++ program. Divide by zero is an easily avoidable condition. If you actually require an exception, simply throw whenever a denominator evaluates 0. Otherwise, just set it to 1, or simply veto the division entirely. You can catch ALL C++ exceptions with catch(...). C++11 improves the handling of the catch-all.Impost
C
39

In short, use catch(...). However, note that catch(...) is meant to be used in conjunction with throw; basically:

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

This is the proper way to use catch(...).

Cadelle answered 8/3, 2014 at 11:36 Comment(5)
its better to using RAII for memory management that automatically handle this exception situations.Potvaliant
@paykoob How does that handle cases where you manged to create a new foo but it failed on a bar. Or when the constructor of bar trys to open a file but fails and therefore throws. then you might end up with a dangeling fooCadelle
@MelleSterk Wouldn't the stack still get cleaned up in that case, which would run Foo's destructor? I thought that was the whole point of RAII. However, if you need a pointer to a Foo rather than just creating the Foo on the stack, then you'd need to wrap the pointer in something else that is declared on the stack.Prichard
yes auto foo = std::make_unique<Foo>(); auto bar = std::make_unique<Bar>(); // is exception safe and will not leak, no catch(...) requiredBuster
Me from the future does indeed agree me from the past did not understand RAII at that timeCadelle
C
23

it is possible to do this by writing:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

But there is a very not noticeable risk here: you can not find the exact type of error that has been thrown in the try block, so use this kind of catch when you are sure that no matter what the type of exception is, the program must persist in the way defined in the catch block.

Calamanco answered 20/9, 2013 at 14:20 Comment(0)
P
19

You can use

catch(...)

but that is very dangerous. In his book Debugging Windows, John Robbins tells a war story about a really nasty bug that was masked by a catch(...) command. You're much better off catching specific exceptions. Catch whatever you think your try block might reasonably throw, but let the code throw an exception higher up if something really unexpected happens.

Pertain answered 25/11, 2008 at 0:16 Comment(2)
I just caught some usages of these and peppered in some logging at that stage. Doing nothing with an exception is definitely asking for trouble.Chelseachelsey
Why trouble? Also can we log some kind of e.what() on exceptions caught within (...)?Dehorn
T
16

Let me just mention this here: the Java

try 
{
...
}
catch (Exception e)
{
...
}

may NOT catch all exceptions! I've actually had this sort of thing happen before, and it's insantiy-provoking; Exception derives from Throwable. So literally, to catch everything, you DON'T want to catch Exceptions; you want to catch Throwable.

I know it sounds nitpicky, but when you've spent several days trying to figure out where the "uncaught exception" came from in code that was surrounded by a try ... catch (Exception e)" block comes from, it sticks with you.

Tremblay answered 25/11, 2008 at 0:31 Comment(7)
Of course, you should never catch Error objects -- if you were supposed to catch them they would be Exceptions. Error objects are completely fatal things, such as running out of heap space etc.Admonitory
Neither runtime exceptions which are most of the times GoodProgrammerExpected exceptions!!!Pennsylvania
We had a really serious bug caused by catching an OutOfMemoryError due to a catch(Throwable) block instead of letting it kill things...Halidom
Of course catch(Exception) may not catch all exceptions in Java, you are getting it mixed up with C#... Java = catch(Thowable), C# = catch(Exception). Don't get them confused.Reeva
@Pennsylvania That sounds like the CoderMalfunctionError (which is actually a real Java Error subclass... though it doesn't mean what it sounds like.)Prichard
Maybe the code catching Throwable or Error or one of the derived classes from Error calls it an exception. But although it is a fault condition, Java explicitly distinguishes errors and exceptions. Your answer here simply muddles it back together again. If you throw an error in your code then you just get the error / stacktrace back (unless the entire system is buggered up, of course).Millardmillboard
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.Exclave
B
12

Well, if you would like to catch all exception to create a minidump for example...

Somebody did the work on Windows.

See http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus In the article, he explains how he found out how to catch all kind of exceptions and he provides code that works.

Here is the list you can catch:

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

And the usage: CCrashHandler ch; ch.SetProcessExceptionHandlers(); // do this for one thread ch.SetThreadExceptionHandlers(); // for each thred


By default, this creates a minidump in the current directory (crashdump.dmp)

Breadnut answered 23/4, 2015 at 16:50 Comment(0)
A
10

Be aware

try{
// ...
} catch (...) {
// ...
}

catches only language-level exceptions, other low-level exceptions/errors like Access Violation and Segmentation Fault wont be caught.

Archegonium answered 25/3, 2020 at 13:40 Comment(6)
Things like Segmentation Fault are not actually exceptions, they are signals; thus, you cannot catch them like typical exceptions. However, there are some workarounds like this.Seamus
what is difference between catch(...) vs catch(std::exception)?Green
@Green catch(...) catches all language level thrown exceptions, on the other hand catch(std::exception) catches only exceptions of type std::exception, for example if you call throw 5 only catch(...) will catch that.Archegonium
Is there any additional cost on catching all exceptions?Dehorn
@Dehorn exception handling does not come for free, so it has a cost compared to no exception or error handling, but if you meant: catching all vs catching specific exception, i believe it is cheaper since no exception type check is there, but of course just an opinion with no proof.Archegonium
@Archegonium I would say if you have less processing cost, you have much more memory cost in this case to carry out all the exceptions.Dehorn
C
6

A generic exception catching mechanism would prove extremely useful.

Doubtful. You already know your code is broken, because it's crashing. Eating exceptions may mask this, but that'll probably just result in even nastier, more subtle bugs.

What you really want is a debugger...

Charleencharlemagne answered 25/11, 2008 at 0:44 Comment(6)
I disagree, there's plenty of cases in real time applications where I'd rather catch an unknown exception, write anything to a log/ pursue some generic error course of action, rather than letting the application crash.Duwe
I rather suspect you're thinking of cases where you can pursue some generic error course of action, conveniently ignoring those where the stack is trashed or memory is exhausted and generic error-handling isn't going to succeed either. Nothing wrong with catching errors that you can recover from, but IMHO a catch-all should really exist only as isolated (separate stack, pre-allocated memory), carefully-written logic called just prior to program termination; if you don't know what the problem is, you can't be confident that it can be recovered from.Charleencharlemagne
I.e. install a signal handler which unwinds some log you build during runtime to figure out where the program crashed and, hopefully, why.Habitat
For example, I have a suite of unit tests. If one test dies, I want to log it, and then keep testing.Evangelinaevangeline
@Charleencharlemagne I totally disagree. You know that on a crash code is broken, but not where. If the code is in production, you want to log it so you can know what happened . User informations are normally bullshit: they don't know what they have done, everything is random. if you don't know what the problem is - it is almost impossible to find it.Bostow
Which is why you really just want to log whatever information is available and terminate, @offler. A core dump isnt much fun, but is certainly less prone to misremembering than the user.Charleencharlemagne
J
4
  1. Can you run your JNI-using Java application from a console window (launch it from a java command line) to see if there is any report of what may have been detected before the JVM was crashed. When running directly as a Java window application, you may be missing messages that would appear if you ran from a console window instead.

  2. Secondly, can you stub your JNI DLL implementation to show that methods in your DLL are being entered from JNI, you are returning properly, etc?

  3. Just in case the problem is with an incorrect use of one of the JNI-interface methods from the C++ code, have you verified that some simple JNI examples compile and work with your setup? I'm thinking in particular of using the JNI-interface methods for converting parameters to native C++ formats and turning function results into Java types. It is useful to stub those to make sure that the data conversions are working and you are not going haywire in the COM-like calls into the JNI interface.

  4. There are other things to check, but it is hard to suggest any without knowing more about what your native Java methods are and what the JNI implementation of them is trying to do. It is not clear that catching an exception from the C++ code level is related to your problem. (You can use the JNI interface to rethrow the exception as a Java one, but it is not clear from what you provide that this is going to help.)

Janelljanella answered 25/11, 2008 at 21:15 Comment(0)
D
3

For the real problem about being unable to properly debug a program that uses JNI (or the bug does not appear when running it under a debugger):

In this case it often helps to add Java wrappers around your JNI calls (i.e. all native methods are private and your public methods in the class call them) that do some basic sanity checking (check that all "objects" are freed and "objects" are not used after freeing) or synchronization (just synchronize all methods from one DLL to a single object instance). Let the java wrapper methods log the mistake and throw an exception.

This will often help to find the real error (which surprisingly is mostly in the Java code that does not obey the semantics of the called functions causing some nasty double-frees or similar) more easily than trying to debug a massively parallel Java program in a native debugger...

If you know the cause, keep the code in your wrapper methods that avoids it. Better have your wrapper methods throw exceptions than your JNI code crash the VM...

Dramaturgy answered 18/1, 2010 at 22:56 Comment(0)
C
2

If you are looking for Windows-specific solution then there is structured exception handling: https://learn.microsoft.com/en-us/cpp/cpp/try-except-statement

The code looks as follows

__try
{
   // code here may throw or make access violation
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
    // after exception code here, e.g. log the error
}

It will catch not only C++ exceptions but also access violations or other system exceptions.

Carnassial answered 13/6, 2021 at 8:45 Comment(0)
L
1

Well this really depends on the compiler environment. gcc does not catch these. Visual Studio and the last Borland that I used did.

So the conclusion about crashes is that it depends on the quality of your development environment.

The C++ specification says that catch(...) must catch any exceptions, but it doesn't in all cases.

At least from what I tried.

Lipkin answered 22/4, 2018 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.