Can I use std::current_exception during stack unwinding? - c++

Should it be possible to use std::current_exception inside destructors of objects that are destroyed during stack unwinding?
Documentation on cppreference says:
If called during exception handling (typically, in a catch clause), captures the current exception object (...)
But it's not clear for me whether stack unwinding is a part of exception handling.
In some highest-ranked answer on stackoverflow author assumes that it's possible.
I did some test on my compiler (g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) and it seems, that std::current_exception returns empty pointer in this case.
#include <exception>
#include <stdexcept>
#include <iostream>
struct A
{
~A()
{
std::clog << "in destructor"<<std::endl;
std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl;
std::clog << "current_exception: " << (bool)std::current_exception() << std::endl;
}
};
int main(int argc, char **)
{
try
{
A aa;
std::clog << "before throw"<<std::endl;
if(argc>1)
throw std::runtime_error("oh no");
}
catch(...)
{
std::clog << "in catch block"<<std::endl;
std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl;
std::clog << "current_exception: " << (bool)std::current_exception() << std::endl;
}
return 0;
}
The output is:
before throw
in destructor
uncaught_exception: 1
current_exception: 0
in catch block
uncaught_exception: 0
current_exception: 1
Does anybody know what the standard says?

C++ Standard defines current_exception() in section § 18.8.5 [propagation] :
(emphasis mine)
exception_ptr current_exception() noexcept;
Returns: An exception_ptr object that refers to the currently handled
exception (15.3) or a copy of the currently handled exception, or a
null exception_ptr object if no exception is being handled. The
referenced object shall remain valid at least as long as there is an
exception_ptr object that refers to it.
And § 15.3 [except.handle], notes 7 and 8 :
A handler is considered active when initialization is complete for the
parameter (if any) of the catch clause. [ Note: The stack will have
been unwound at that point. — end note ]
The exception with the most recently activated handler that is still
active is called the currently handled exception.
The exception returned by current_exception() is defined as the "currently handled exception", which is the exception of the most recent active handler, and a handler is active only when stack unwinding completed.
As your tests have shown, there is no "active handler" during stack unwinding, so there is no "currently handled exception" either : in that case, current_exception() will return a null exception_ptr.

Related

Throwing an exception which causes a destructor to be called crashes the program

Consider this small snippet of code, which is actually part of a larger codebase:
class A
{
public:
A()
{
std::cout << "A" << std::endl;
}
~A()
{
std::cout << "~A" << std::endl;
}
};
void f()
{
A a;
throw;
}
void g()
{
try
{
f();
}
catch(...)
{
std::cout << "Caught" << std::endl;
}
}
For my particular case, the output turns out to be
A
~A
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
It seems that rather than the exception being caught, the program is just terminated. However, if I remove A's constructor, the exception does get caught.
Without closely analyzing the code, is it possible to know what causes this sort of behaviour?
A throw-expression with no operand, as in your code:
Rethrows the currently handled exception (the same object, not a copy of it)
Or, if there is no currently handled exception, calls std::terminate.
I am assuming f() is not being called while an exception is being handled (I imagine you're calling it directly from main or something). Thus, std::terminate is called.
The object a is irrelevant.

Is GotW #47 halfly wrong?

GotW #47
The Wrong Solution
"Aha," many people -- including many experts -- have said, "let's use uncaught_exception() to figure out whether we can throw or not!" And that's where the code in Question 2 comes from... it's an attempt to solve the illustrated problem:
// The wrong solution
//
T::~T() {
if( !std::uncaught_exception() ) {
// ... code that could throw ...
} else {
// ... code that won't throw ...
}
}
The idea is that "we'll use the path that could throw as long as it's safe to throw." This philosophy is wrong on two counts: first, this code doesn't do that; second (and more importantly), the philosophy itself is in error.
The Wrong Solution: Why the Code Is Unsound
One problem is that the above code won't actually work as expected in some situations. Consider:
// Why the wrong solution is wrong
//
U::~U() {
try {
T t;
// do work
} catch( ... ) {
// clean up
}
}
If a U object is destroyed due to stack unwinding during to exception propagation, T::~T will fail to use the "code that could throw" path even though it safely could.
I believe that explanation above is completely incorrect, if std::uncaught_exception returns true it is ALWAYS unsafe to let any function including destructor to exit with another exception. Prove
If any function that is called during stack unwinding, after initialization of the exception object and before the start of the exception handler, exits with an exception, std::terminate is called. Such functions include destructors of objects with automatic storage duration whose scopes are exited, and the copy constructor of the exception object that is called (if not elided) to initialize catch-by-value arguments.
Same words in c++ (terminate is called in ~YYY()):
#include <exception>
#include <iostream>
int main(int argc, char* argv[])
{
struct YYY
{
~YYY()
{
std::cout << "during stack unwinding before throwing second exception " << std::uncaught_exception() << std::endl;
throw std::exception();
}
};
struct XXX
{
~XXX()
{
std::cout << "after first exception thrown but not catched " << std::uncaught_exception() << std::endl;
if (std::uncaught_exception())
{
try
{
YYY yyy;
}
catch (const std::exception&)
{
std::cout << "in second exception catch block " << std::uncaught_exception() << std::endl;
}
}
}
};
try
{
XXX xxx;
std::cout << "before throwing first exception " << std::uncaught_exception() << std::endl;
throw std::exception();
}
catch (const std::exception&)
{
std::cout << "in first exception catch block " << std::uncaught_exception() << std::endl;
}
std::cout << "after both exceptions catched " << std::uncaught_exception() << std::endl;
return 0;
}
My question is did I miss something and Herb Sutter is right for some specific case or he is absolutely wrong in this piece of the explanation?
It is a question of what is meant by "any function that is called during stack unwinding" in the standard text.
I believe the intent was to prevent "any function that is called directly by the stack unwinding mechanism" to terminate with an exception, i.e. to throw another (new) exception into the active stack unwinding session. This requirement is not supposed to apply to any subsequent (nested) functions calls made internally by any function that is called by the original stack unwinding session.
As long as new exceptions are thrown and caught internally, without being allowed to escape into the active stack unwinding session, they are allowed. Herb's explanation is in full agreement with the standard: it is possible to throw new exceptions during stack unwinding as long as they are intercepted and suppressed internally.
Your example calls terminate() for a different reason. You are probably compiling with post-C++11 compiler. In C++11 destructors are noexpect by default, which is why your YYY::~YYY() simply calls terminate() regardless of whether stack unwinding is in progress, or of any other external conditions (GCC will even warn you about exactly that).
Declare it as
~YYY() throw(std::exception) // or `noexcept(false)`
{
...
to test the intended behavior of the code. And no, it does not call terminate(): http://coliru.stacked-crooked.com/a/296ffb43b774409e
Herb's outdated code, obviously, suffers from the same problem.

C++ throwing an exception from a destructor

This isn't a question on whether it's safe to throw an exception from a destructor.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9 states:
"During stack unwinding, all the local objects in all those stack frames are destructed. If one of those destructors throws an exception (say it throws a Bar object), the C++ runtime system is in a no-win situation: should it ignore the Bar and end up in the } catch (Foo e) { where it was originally headed? Should it ignore the Foo and look for a } catch (Bar e) { handler? There is no good answer — either choice loses information."
IE: if during stack unwinding another exception is thrown, then the runtime system is in a no-win situation because the catch handler to 'look for' is ambiguous.
Is there an 'exception' to the above, when the exception that is thrown during stack unwinding itself is in a try/catch block? In this case there is no ambiguity:
#include <iostream>
using namespace std;
class Component
{
public:
~Component()
{
cout << "In component destructor" << endl;
try
{
throw 1;
}
catch (...)
{
cout << "Caught exception in component destructor" << endl;
}
}
};
class Container
{
public:
~Container()
{
cout << "In container destructor" << endl;
Component component;
}
}
;
int main()
{
try
{
Container cont;
throw 'a';
}
catch (...)
{
cout << "Caught main exception ok" << endl;
}
return 0;
}
The following implies it, but I was wondering if anyone knew of the relevant C++ standard sections.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr155.htm
"If during stack unwinding a destructor throws an exception and that exception is not handled, the terminate() function is called. The following example demonstrates this:"
Your Component destructor is safe. The rule you're quoting only applies if the exception is thrown out of the destructor (i.e., to the destructor's caller.)
EDIT: Here's one relevant quote from the standard (emphasis added)
Note: If a destructor called during
stack unwinding exits with an
exception, std::terminate is called
(15.5.1).

Does catch (...) work on throw; with no object?

What does C++ standard say should happen for the following code when there is no pending exception being processed higher up the stack?
try {
throw;
} catch (...) {
cerr << "Caught exception." << endl;
}
Will the throw with no object be caught or not?
From the 2003 C++ Standard §15.1[except.throw]/8:
If no exception is presently being handled, executing a throw-expression with no operand calls terminate().
So, in your example, since no exception is currently being handled, nothing is thrown and instead terminate() is called. Since terminate() does not return, your catch block will never be entered.

Confusion in exception handling

Consider the following program
#include <iostream>
#include<cstdlib>
using namespace std;
class E {
public:
const char* error;
E(const char* arg) : error(arg) { }
};
void my_terminate() {
cout << "Call to my_terminate" << endl;
}
struct A {
A() { cout << "In constructor of A" << endl; }
~A(){
cout << "In destructor of A" << endl;
throw E("Exception thrown in ~A()");
}
};
struct B {
B() { cout << "In constructor of B" << endl; }
~B() { cout << "In destructor of B" << endl; }
};
int main() {
set_terminate(my_terminate);
try {
cout << "In try block" << endl;
A a;
B b;
throw E("Exception thrown in try block of main()"); // Line 36
}
catch (E& e) {
cout << "Exception: " << e.error << endl;
}
catch (...) {
cout << "Some exception caught in main()" << endl;
}
cout << "Resume execution of main()" << endl;
}
Output:
In try block
In constructor of A
In constructor of B
In destructor of B
In destructor of A
Call to my_terminate
Disallowed system call: SYS_kill
In line 36 an exception is thrown from the try block in main. Now why is this exception not caught by the handler?
Rather the 'stack unwinding' process continues.The destructor of A throws an exception too which is again not caught by any handler,instead a call to my_terminate is made, why?
Why is the handler not called in the two cases?
The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception.
You throw an exception in A's destructor, which is something you are not supposed to do.
When you throw the original E temporary from the try block in main, the runtime implementation constructs an exception object of type E and searches for the first catch block that can handle the exception. In this case, this is the immediately following catch (E& e) block.
When the implementation finds the correct catch to handle the exception, it then destroys all automatic variables which must go out of scope by moving out of the scope where the throw occurred to the scope in which the catch resides.
In this case the objects a and b which are local to the catch block go out of scope, so must be destroyed (in the reverse order that they were created). However, destroying a causes another exception to be thrown. Because the implementation already has an uncaught exception and has already chosen a catch handler for that exception which it is trying to reach, there is no mechanism to handle this new exception. The rule in this case is that std::terminate, and in your case your terminate handler, is called immediately.
You should note that your my_terminate function is not a conforming terminate_handler, as a terminate_handler must not return and must terminate the program execution (i.e. must not throw either). Yours returns implicitly.
set_terminate
function installs term_func as the function called by terminate. set_terminate is used with C++ exception handling and may be called at any point in your program before the exception is thrown. terminate calls abort by default. You can change this default by writing your own termination function and calling set_terminate with the name of your function as its argument. terminate calls the last function given as an argument to set_terminate. After performing any desired cleanup tasks,
term_func should exit the program.
If it does not exit (if it returns to its caller), abort is called.
my_terminate() should look like :
void my_terminate()
{
cout << "Call to my_terminate" << endl;
*
*
*
exit(-1);
}
In section 15.2 of my draft standard it states:
3 The process of calling destructors
for automatic objects constructed on
the path from a try block to a
throw-expression is called “stack
unwinding.” [ Note: If a destructor
called during stack unwinding exits
with an exception, std::terminate is
called (15.5.1). So destructors should
generally catch exceptions and not let
them propagate out of the destructor.
—end note ]
They have defined "stack unwinding" broadly enough that it seems to cover this case, even if it is all happening within one function. I guess it's somewhat clear that implementations expect destructors not to try and propagate exceptions outward.
Here is the problem. Your A's destructor throws, which is a bad thing. Re-throwing exceptions, or throwing a new exception in an exception handler is kosher because the stack-unwinding is well-behaved. In that case, only one exception is alive at the current stack frame. When a destructor throws an exception during the stack unwinding process however, two exceptions are alive the same stack frame, i.e they unwind the stack on the same level. In your case, that's two E objects. So which one does one choose to follow? You cannot follow both, so the standard says that terminate() will be called. You can make the exception system use your custom terminate routine by passing one with std::set_terminate() from the header <exception>.
You seem to think that your std::terminate() handler can resume your program by returning, but that's undefined behavior.
If you absolutely positively need to throw from a destructor and can't contain it with an exception handler inside the destructor itself, here is a workaround:
The function uncaught_exception() from the header <exception> returns true if an exception has been thrown, but not yet caught. If it returns true, that means that the process is in the middle of a stack unwinding, unwinding the stack and calling destructors until it finds a proper exception handler. Use the function inside destructors which throw, so that they only throw when a stack unwinding is not happening.
Here's an example on how to use uncaught_exception() (Though, it's an extremely bad idea):
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
#include <cstdlib>
void termhandler()
{
std::cout << "Inside terminate()" << std::endl;
abort();
}
class Foo
{
public:
Foo(int val) : i(val){ std::cout << "Created Foo object " << i << std::endl; }
~Foo()
{
if(std::uncaught_exception()){
std::cout << "~Foo::Foo() object " << i << " : " << "Stack unwinding in progress. Can't throw!" << std::endl;
} else {
std::cout << "~Foo::Foo() object " << i << " : " << "Throwing test exception." << std::endl;
std::ostringstream strm;
strm << i;
std::runtime_error e("Exception from ~Foo::Foo() object " + strm.str());
throw e;
}
}
int i;
};
int main()
{
try {
std::set_terminate(termhandler);
Foo A(1);
Foo B(2);
} catch(std::exception& e){
std::cout << "Caught exception in main() : " << e.what() << std::endl;
}
}
Which gives the following output:
Created Foo object 1
Created Foo object 2
~Foo::Foo() object 2 : Throwing test exception.
~Foo::Foo() object 1 : Stack unwinding in progress. Can't throw!
Caught exception in main() : Exception from ~Foo::Foo() object 2