Is it safe to throw / catch on stack unwind? - c++

Q: Is it safe to throw and catch an exception on stack unwind, or does the application call terminate on the second throw?
minimal example:
void some_function()
{
try
{
// do stuff here that can throw
throw std::runtime_error("blah");
} catch(const std::exception& re)
{
try // this code could be in some function called from here
{
// do something with re here that throws a logical_error
throw std::logical_error("blah blah"); // does this call terminate?
} catch(const std::logical_error& le)
{
}
}
}
I got curious after reading this question.
Note: I know you can/should catch(...) in a destructor, but does it make sense in general to have a try/catch in a catch block - maybe in some function called on the exception (re in my example)?

That's not really during stack unwinding. Once a catch block is entered, the stack has already been unwound.
And yes, that code is legal. See this question: Nested try...catch inside C++ exception handler?

Pubby's answer best answers the scenario you're describing.
As an addendum, while a stack is unwinding, the only user code that's executed is destructors (and the code those destructors call).
If you do throw in a destructor during this scenario, the standard specifies that std::terminate() will be called.

Related

Will throwing an exception in a catch block lead to two exceptions being in flight? [duplicate]

This question already has answers here:
Nested try...catch inside C++ exception handler?
(2 answers)
Closed 1 year ago.
Consider the following C++ code:
class MyException {};
void someFunction()
{
try
{
/// ... code that may throw
}
catch(std::exception& e )
{
throw MyException();
}
}
Question
Is the exception e absorbed at the beginnging of the catch block or at the end of the catch block?
In the second case throwing the new exception would result in having two exceptions in flight, what is not what I want. I want to absorb the std::exception and start one of my own type.
No. That's how one should do it. The throw myException() can only occur if the first exception has been caught and hence is no longer 'in flight'.
This design pattern is quite common to 'translate' error messages coming from another library that your code is using to an error that the user of your code can better relate to.
Alternatively, if you want to do more than merely throw (say you want to do some clearing up of resources -- though that should really be done via RAII, i.e. from destructors), then you can simply rethrow the original exception via
try
{
// ... code that may throw
}
catch(...) // catches anything
{
// ... code that runs before rethrowing
throw; // rethrows the original catch
}
just throw; statement is enough in catch block to rethrow same exception in higher context.
It throws SAME exception again. No new exception is generated. So no fight :)
In case you want to catch exception of type A and then throw exception of type B, then the way you did it is absolute correct.
In this case, old exception (type A) is caught(absorbed) and only new exception(type B) is thrown to higher context. So, again no fight :)

Rethrow from a function in the catch block

In this case, I have want to perform some actions based on the exception thrown and then re-throw the exception. Is this recommended - My aim is to do some work based on the exception thrown and rethrow it and have the application crash and generate dump that have the call stack in the exception.
class Foo
{
public:
void HandleException(const std::exception& ex)
{
// Log, report some metrics
throw;
}
void Work(//Some inputs)
{
try
{
// trying doing some work
}
catch (const std::exception& ex)
{
// This is really an exceptional situation, and the exception should be thrown which
// cause the exe to abort and create dump.
// Intention is to preserve call stack and have it in dump.
HandleException(ex);
}
}
}
Let me add another note to the question: When I have HandleException as a lambda function, throw in the lambda causes exception. Do I need to capture some state and how do I do that ?
When you catch an exception you have two options:
Achieve the original goal (contract) in some way, e.g. by retrying.
Report failure by throwing.
Rethrowing the original exception is one way to implement the second bullet point.
Yes that is valid. BUT it is also dangerous.
If you call throw; with no parameters and there is no exception currently in flight this will result in a call to std::terminate(). The problem with your current code is that anybody can call the function even when they are not in a catch block (which would result in termination).
So you may want to validate that an exception is propogating:
void HandleException(const std::exception& ex)
{
// Log, report some metrics
if (std::uncaught_exception()) {
throw;
}
// Maybe put an else here.
}
Also worth reading: GotW #47: Uncaught Exceptions

c++ exception handling

Learning "try & catch". What is wrong with the following code?
Thanks for the advice.
Error in execution:
terminate called without an active exception
Aborted
The code:
#include <stdio.h>
int main()
{
int a = 3;
try
{
if (a < 5)
throw;
}
catch (...)
{
printf ("captured\n");
}
return 0;
}
Your throw; statement tries to rethrow a current exception but there probably isn't one. You need something like
throw some_exception_object();
Inside of a try block, you have to specify what to throw. The only place you can use throw by itself is inside of a catch block to re-throw the current exception. If you call throw by itself without a current exception being active, you will kill your app, as you have already discovered.
Try this:
#include <stdio.h>
int main()
{
int a = 3;
try
{
if (a < 5)
throw 1; // throws an int
}
catch (...)
{
printf ("captured\n");
}
return 0;
}
You can throw anything you want, as long as you throw something.
There are four things, two major and two minor. One thing at a time...
1. Rethrow usage w/o active exception
A throw; statement is used to re-throw an exception that is currently caught. For example:
try {
do_something();
} catch (const std::exception &) {
throw; // This statement re-throws an exception that was caught in this "catch" block.
}
In your case, you are using throw; without catching any exceptions (in order words — it does not appear inside catch block directly or indirectly), thus your program is terminated. When there is a need to throw and not to re-throw an exception, like in your case, you must specify an exception object to be thrown. For example:
throw std::runtime_error("Something bad happened");
2. catch-all clause which does not re-throw a caught exception
Your catch-all clause (catch (...)) is perfectly legal C++. However, it does not re-throw caught exception. Even though it is a legal C++ code, such a usage is a taboo. C and C++ runtime is usually using special types of exceptions to implement certain functionality. For example, NPTL is using exceptions to implement a thread cancellation. If you catch that exception using catch (...), a thread won't be cancelled and you are going to have a bad time. Generally, you have to catch exceptions by their types. In almost all cases, exceptions are inherited from std::exception, and so you have to write catch (const std::exception &) or, if you expect to catch an exact type, - catch(const TypeYouExpect &). If you must, however, use catch-all, remember to re-throw. For example:
try {
do_something();
} catch (...) {
throw; // DO NOT FORGET TO RE-THROW.
}
3. Header naming...
You are including C header whereas C++ provides its own headers for standard C features. So, header:
#include <stdio.h>
.. should be:
#include <cstdio>
C++ specific C functions get special treatment. For example, they become available in std namespace. So that you can use std::open() instead of just open() or ::open(). No big deal, but is highly recommended way to go.
4. Return from main.
Unlike C, C++'s main() function is very special. It allows you not to have return 0;. This is a default behavior. So, unless you really need to return some value, you may save yourself some time by not typing return 0;. Remember, however, that main is the only function like that, and that everywhere else you must explicitly return something unless a function is marked void.
Hope it helps. Good Luck!
You need to actually throw some object. Even something as simple as
throw "error";
will catch the error like you want it to.
see it in action here
The statement to throw an exception is:
throw <expression>;
This statement:
throw;
is also called the re-throw statement and is use to re-throw an existing exception that has been caught. It is typically used in a catch block, for example, you look at the exception and decide if you can continue, retry or abort. In case you decide to abort, you re-throw the exception so that somebody else down the call stack will catch it and handle this error.
For example:
// getResult() calls can fail with a deadlock exception
// This method will retry up to 3 times before failing
Result getResultWithRetry()
{
int nbTry = 3;
for(;;) {
try {
return getResult();
} catch (DeadLockException& e) {
if (nbTry == 0) {
throw; // re-throw the deadlock exception
}
}
--nbTry;
}
}

What does a single "throw;" statement do?

These days, I have been reading a lot the C++ F.A.Q and especially this page.
Reading through the section I discovered a "technique" that the author calls "exception dispatcher" that allows someone to group all his exception handling in one handy function:
void handleException()
{
try {
throw; // ?!
}
catch (MyException& e) {
//...code to handle MyException...
}
catch (YourException& e) {
//...code to handle YourException...
}
}
void f()
{
try {
//...something that might throw...
}
catch (...) {
handleException();
}
}
What bothers me is the single throw; statement: if you consider the given example then sure, it is obvious what it does: it rethrows the exception first caught in f() and deals with it again.
But what if I call handleException() on its own, directly, without doing it from a catch() clause ? Is there any specified behavior ?
Additionally for bonus points, is there any other "weird" (probably not the good word) use of throw that you know of ?
Thank you.
If you do a throw; on its own, and there isn't a current exception for it to rethrow, then the program ends abruptly. (More specifically, terminate() is called.)
Note that throw; is the only safe way to re-throw the current exception - it's not equivalent to
catch (exception const & e) { throw e; }
Yes, it specified behavior, it will call terminate;
15.1, para 8: If no exception is presently being handled, executing a
throw expression with no operand calls
terminate() (15.5.1).
That's so-called exception handler. It rethrows the "current exception" if any. If there's no exception currently being handled terminate() will be called.

Reasons for stack unwinding fail

I was debugging an application and encountered following code:
int Func()
{
try
{
CSingleLock aLock(&m_CriticalSection, TRUE);
{
//user code
}
}
catch(...)
{
//exception handling
}
return -1;
}
m_CriticalSection is CCricialSection.
I found that user code throws an exception such that m_CriticalSection is not released at all. That means due to some reasons stack is corrupted and hence unwinding failed.
My question is:
1) In what different scenarios stack unwinding can fail ?
2) what different possibility of exception can be thrown such that stack unwinding fails.
3) Can I solve this problem by putting CSingleLock outside of try block ?
Thanks,
Are you getting an abnormal program termination?
I believe your CCriticalSection object will be released CSingleLock's destructor. The destructor will get called always since this is an object on the stack. When the usercode throws, all stacks between the throw and the catch in your function will be unwound.
However, chances are that some other object in your user code or even the CSingleLock destructor has thrown another exception in the meantime. In this case the m_CriticalSection object will not get released properly and std::terminate is called and your program dies.
Here's some sample to demonstrate. Note: I am using a std::terminate handler function to notify me of the state. You can also use the std::uncaught_exception to see if there are any uncaught exceptions. There is a nice discussion and sample code on this here.
struct S {
S() { std::cout << __FUNCTION__ << std::endl; }
~S() { throw __FUNCTION__; std::cout << __FUNCTION__ << std::endl; }
};
void func() {
try {
S s;
{
throw 42;
}
} catch(int e) {
std::cout << "Exception: " << e << std::endl;
}
}
void rip() {
std::cout << " help me, O mighty Lord!\n"; // pray
}
int main() {
std::set_terminate(rip);
try {
func();
}
catch(char *se) {
std::cout << "Exception: " << se << std::endl;
}
}
Read this FAQ for clarity.
Can I solve this problem by putting CSingleLock outside of try block ?
Hard to say without having a look at the stack and error(s)/crashes. Why don't you give it a try. It may also introduce a subtle bug by hiding the real problem.
Let me start by saying that I don't know what CSingleLock and CCriticalSection do.
What I do know is that an exception thrown in your "user code" section should unwind the stack and destroy any variables that were created within the try { } block.
To my eyes, I would expect your aLock variable to be destroyed by an exception, but not m_CriticalSection. You are passing a pointer to m_CriticalSection to the aLock variable, but the m_CriticalSection object already exists, and was created elsewhere.
are you sure that lifetime of your m_CriticalSection is longer that CSingleLock?
maybe someone corrupt your stack?
3) Can I solve this problem by putting CSingleLock outside of try block ?
in this case - yes. But remember, it is not good thing for performance to put large block in mutex.
btw, catch(...) is not good practice in general. in Win32 it (catch(...)) catching SEH exceptions too, not only c++ exception. maybe you have core in this function and catch it with catch(...).
My question is:
1) In what different scenarios stack unwinding can fail ?
If exit() terminate() abort() or unexpected() are called.
With the exception of a direct calls what situations are any of these likely to happen:
An unhandeled exception is thrown. (Does not apply here)
throw an exception from a destructor while another exception is popogating
2) what different possibility of exception can be thrown such that stack unwinding fails.
Exception thrown from constructor of throw expression
Exception thrown from destructor while exception propogating.
Exception thrown that is never caught (implementatin defined if this actually unwinds stack).
Exception thrown that is not specified in exception specification.
Exception thrown across a C ABI.
Exception thrown inside a thread that is not caught (Implementation defined what happens)
3) Can I solve this problem by putting CSingleLock outside of try block ?
No. All of the above cause the application to terminate without further unwinding of the stack.