Is GotW #47 halfly wrong? - c++

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.

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.

std::shared_ptr: Custom deleter not being invoked

I'm working through C++ Primer, 5th edition, and the author has presented an example to do with using shared_ptrs to manage resources from older libraries that could leak memory, to prevent them from doing so. I decided to create a test to see how it works, but my custom deleter doesn't get called after the exception is thrown and (deliberately) not caught:
#include <iostream>
#include <memory>
#include <string>
struct Connection {};
Connection* Connect(std::string host)
{
std::cout << "Connecting to " << host << std::endl;
return new Connection;
}
void Disconnect(Connection* connection)
{
std::cout << "Disconnected" << std::endl;
delete connection;
}
void EndConnection(Connection* connection)
{
std::cerr << "Calling disconnect." << std::endl << std::flush;
Disconnect(connection);
}
void AttemptLeak()
{
Connection* c = Connect("www.google.co.uk");
std::shared_ptr<Connection> connection(c, EndConnection);
// Intentionally let the exception bubble up.
throw;
}
int main()
{
AttemptLeak();
return 0;
}
It produces the following output:
Connecting to www.google.co.uk
My understanding is that when a function is exited, whether that's exiting normally or because of an exception, the local variables will all be destroyed. In this case, that should mean connection being destroyed when AttemptLeaks() exits, invoking its destructor, which should then call EndConnection(). Notice also that I'm using, and flushing, cerr, but that also didn't give any output.
Is there something wrong with my example, or my understanding?
Edit: While I already have the answer to this question, for anyone else that stumbles upon this in the future, my problem was with my understanding of how throw works. Although the answers below correctly state how to use it, I think it's best to explicitly make it clear that I was (incorrectly) trying to use it to 'generate' an unhandled exception, to test my code above.
Bare throw is intended for use inside catch blocks to rethrow a caught exception. If you use it outside a catch block, terminate() will be called and your program ends at once. See what does "throw;" outside a catch block do?
If you delete the throw-statement the shared_ptr connection will go out of scope and should call the deleter. If you have any doubts about the exception-safety of using a shared_ptr (I don't ;), you can explicitly throw an exception here by changing throw to throw 1.
The throw expression without an operand is intended for rethrowing the exception being currently handled. If no exception is being handled then std::terminate is called. In this situation stack unwinding does not take place, which is why the deleter is never being called. Change your code to the folowing:
void AttemptLeak()
{
Connection* c = Connect("www.google.co.uk");
std::shared_ptr<Connection> connection(c, EndConnection);
// Intentionally let the exception bubble up.
throw 42; // or preferably something defined in <stdexcept>
}
int main()
{
try {
AttemptLeak();
} catch(...) {
}
return 0;
}
Now the deleter will be called when the shared_ptr goes out of scope.

intermixing c++ exception handling and SEH (windows)

I have a function in which I call getaddrinfo() to get an sockaddr* which targets memory is allocated by the system.
As many may know, you need to call freeaddrinfo() to free the memory allocated by getaddrinfo().
Now, in my function, there are a few places, where I may throw an exception, because some function failed.
My first solution was to incorporate the freeaddrinfo() into every if-block.
But that did look ugly for me, because I would have had to call it anyways before my function returns, so I came up with SEH`s try-finally...
But the problem I encountered is, that it is not allowed to code the throw-statements into the __try-block
Then, I read on the msdn and tried to swap the throw-statements into the helper function called from within the __try-block... and voila, the compiler didn´t moan it anymore...
Why is that? And is this safe? This does not make sense to me :/
Code:
void function()
{
//...
addrinfo* pFinal;
__try
{
getaddrinfo(..., &pFinal);
//if(DoSomething1() == FAILED)
// throw(exception); //error C2712: Cannot use __try in functions that require object unwinding
//but this works
Helper();
//...
}
__finally
{
freeaddrinfo();
}
}
void Helper()
{
throw(Exception);
}
EDIT:
tried the following and it works with throwing an integer, but does not when i use a class as an exception:
class X
{
public:
X(){};
~X(){};
};
void Helper()
{
throw(X());
}
void base()
{
__try
{
std::cout << "entering __try\n";
Helper();
std::cout << "leaving __try\n";
}
__finally
{
std::cout << "in __finally\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
try
{
base();
}
catch(int& X)
{
std::cout << "caught a X" << std::endl;
}
std::cin.get();
return 0;
}
Why? :/
You can't mix the two exception types. Under the covers, C++ exceptions use SEH and your SEH exception handler could mess up the exception propogation logic. As a result, the C++ compiler won't allow you to mix them.
PS: Structured Exception Handling is almost always a VERY bad idea. Internally Microsoft has banned the use of SEH except in very limited circumstances. Any component that does use structured exception handling is automatically subject to intense code reviews (we have tools that scan code looking for its use to ensure that no cases are missed).
The problem with SEH is that it's extremely easy to accidentally introduce security vulnerabilities when using SEH.
You could wrap the addrinfo in a class that calls getaddrinfo in the constructor and freeaddrinfo in its destructor.
That way it will always be freed, whether there is an exception thrown or not.
catch(int& X)
{
std::cout << "caught a X" << std::endl;
}
That doesn't catch an X, it catches an int&. Since there is no matching catch block, the exception is uncaught, stack unwinding doesn't occur, and __finally handlers don't run.
You can put catch (...) in your thread entrypoint (which is main() for the primary thread) in order to make sure that stack unwinding occurs, although some exceptions are unrecoverable, that's never true of a C++ exception.

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

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.