I am not able to understand how is it possible for std::async to store any exception, not just something derived from std::exception. I played around with the code below
#include <iostream>
#include <future>
#include <chrono>
void f()
{
std::cout << "\t\tIn f() we throw an exception" << std::endl;
throw 1; // throw an int
}
int main()
{
std::future<void> fut = std::async(std::launch::async, f);
std::cout << "Main thread sleeping 1s..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // sleep one second
std::cout << "Main thread waking up" << std::endl;
try
{
fut.get();
}
catch(...)
{
std::cout << "We caught an exception!" << std::endl;
throw; // rethrow
}
}
I launch f() asynchronously, then throw an int inside f. Magically, this int is caught and stored by the future returned by std::async. I understand that is possible to catch(...) the exception in std::async, but how can the latter store it without knowing the exception type? The exception is not derived from some base class (in this case one perhaps can "clone" it via some Base::clone), but can be any exception. Can we somehow magically "deduce" the exception type?
To summarize, my question is:
How can we store an arbitrary exception inside an object then re-throw it at some later time, without knowing the exception type?
std::async could be implemented on top of std::thread and std::packaged_task.
std::packaged_task could be implemented (partly) on top of std::exception_ptr and related function (except that thread-exit ready function).
std::exception_ptr and related functions cannot be written in C++.
I'm not sure if this exactly answers your question, but this example might be helpful.
I compiled the following:
int main()
{
throw 1;
}
with the command
g++ -fdump-tree-gimple -std=c++11 main.cpp -o main
The gimple (gcc's intermediate output) is:
int main() ()
{
void * D.1970;
int D.1974;
D.1970 = __cxa_allocate_exception (4);
try
{
MEM[(int *)D.1970] = 1;
}
catch
{
__cxa_free_exception (D.1970);
}
__cxa_throw (D.1970, &_ZTIi, 0B);
D.1974 = 0;
return D.1974;
}
So it calls __cxa_throw with the address of the a symbol that represents a type. In this case the type is _ZTIi, which is the mangled type of an integer.
Types not available at compile time
The type symbols only need to be available at run time. In a dynamic library that is trying to hide as many symbols as it can, it needs to make sure that any exceptions that aren't caught and dealt with internally are available. For more info, see https://gcc.gnu.org/wiki/Visibility, particularly the section Problems with C++ exceptions (please read!).
It would be interesting to see how this worked between dynamic libraries compiled with different compilers that had different naming schemes.
Related
Good Morning!
Edit: This is not a duplicate as it specifically pertains to SEH, not code-level thrown exceptions.
I'm using SEH to catch hardware errors thrown by some unreliable libraries. I'd like to get more information from the catchall exception. The following code simulates what I'm doing. As you can see, I'm using boost's current_exception_diagnostic_information, but it just spits out "No diagnostic information available." - not terribly helpful.
Is it possible to, at a minimum, get the termination code that would have been returned had the exception not have been caught? (In this case 0xC0000005, Access Violation)
#include "stdafx.h"
#include <future>
#include <iostream>
#include <boost/exception/diagnostic_information.hpp>
int slowTask()
{
//simulates a dodgy bit of code
int* a = new int[5]();
a[9000009] = 3;
std::cout << a[9000009];
return 0;
}
int main()
{
{
try
{
std::future<int> result(std::async(slowTask));
std::cout<< result.get();
}
catch(...)
{
std::cout << "Something has gone dreadfully wrong:"
<< boost::current_exception_diagnostic_information()
<< ":That's all I know."
<< std::endl;
}
}
return 0;
}
Using catch (...) you get no information at all, whether about C++ exceptions or SEH. So global handlers are not the solution.
However, you can get SEH information through a C++ exception handler (catch), as long as you also use set_se_translator(). The type of the catch should match the C++ exception built and thrown inside your translator.
The function that you write must be a native-compiled function (not compiled with /clr). It must take an unsigned integer and a pointer to a Win32 _EXCEPTION_POINTERS structure as arguments. The arguments are the return values of calls to the Win32 API GetExceptionCode and GetExceptionInformation functions, respectively.
Or you can use __try/__except, which are specific to SEH. They can be used inside C++ just fine, including in programs where C++ exceptions are used, as long as you don't have SEH __try and C++ try in the same function (to trap both types of exceptions in the same block, use a helper function).
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.
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.
In the code below i use try/catch in the python module code. In the try block i have a simple error (memory access violation) and trying to catch the corresponding exception and to terminate the program quietly without generation of the .stackdump file. However the latter is still generated what implies that try/catch construct does not do its job. How could i avoid generating .stackdump file and exit the program without errors when the improper operation (like one in the code) is met?
P.S. i'm compiling the code in cygwin with gcc and boost.python
It is interesting that it doesn't work only in case x[3]=2, but works for all other cases: e.g. x[4]=2 or x[20]=2 or, obviously, x[2]=2.
#include <boost/python.hpp>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace boost::python;
class Hello
{
std::string _msg;
public:
Hello(std::string msg){_msg = msg;}
void run(){
try{
double* x;
x = new double[3];
x[3] = 2.0;
delete [] x;
}catch(...){ exit(0); }
}
};
BOOST_PYTHON_MODULE(xyz)
{
class_<Hello>("Hello", init<std::string>())
.def("run",&Hello::run)
;
}
EDIT:
According to what Maciek has suggested i tried the following trick:
Make signal handling function to throw an exception, but not exit
void sig_action(int signo) {
std::cout << "SIGNAL " << signo << std::endl;
throw 1;
// exit(0);
}
And now try to enclose a possibly problematic function in try/catch block (signal function is placed in class constructor):
class Hello
{
std::string _msg;
public:
Hello(std::string msg){
_msg = msg;
signal(SIGABRT, sig_action);
signal(SIGSEGV, sig_action);
}
void set(std::string msg) { this->_msg = msg; }
std::string greet() { return _msg; }
void run(){
try{
double* x;
x = new double[3];
x[3] = 2.0;
delete [] x;
}catch(...){ cout<<"error in function run()\n"; exit(0); }
}
};
However such a trick doesn't work as i expected it produces the following output:
SIGNAL 6
terminate called after throwing an instance of 'int'
SIGNAL 6
terminate called recursively
SIGNAL 6
terminate called recursively
....
(and many more times the same)
So the exception is thrown, but everything finishes before it has been caught. Is there any way to let it be caught before terminating the process?
You can only catch exceptions that are thrown. An invalid pointer access doesn’t throw an exception, it simply causes undefined behaviour, and in your particular case it results in a stack dump.
If you want to catch such a situation situation, use std::vector and the at function to access items. This will throw std::out_of_range when used with an invalid index. However, it’s usually better to avoid the possibility of such accesses a priori since they are usually indicative of a bug in your program, and bugs should not be handled via exceptions, they should be removed from the code.
On linux core dumps are generated by signal handlers with default action set to core (SIGABRT, SIGSEGV, ...). If you want to avoid core dump you can always capture/ignore those signals. It should work on Cygwin stackdumps as well. But you will still probably get some nasty message as output.
EDIT:
#include <signal.h>
// [...]
void sig_action(int signo) {
std::cout << "SIGNAL " << signo << std::endl;
exit(0);
}
int main(int argc, char* argv[]) {
signal(SIGABRT, sig_action);
signal(SIGSEGV, sig_action);
Hello h("msg");
h.run();
}
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.