First some context :
I am testing the robustness of some C-written service, running in an embedded Linux. All my tests are written in C++ and invoke the C API of the service.
Note that the service and the application are running in 2 separate processes. The application opens a proxy within its context to communicate to the service over tcp/ip.
To check an ill-coded callback could not break the service, I am giving it a function which simply throws a C++ exception. As expected, throwing an exception within this C-callback is causing the application to crash.
The service appears so far to be robust to this : the callback is called from a thread which is running in the context of the client application. This means, only the client application is crashed, and the service remains alive.
When I say the application crashes, I mean that it receives a SIGABRT signal, here is the callstack from gdb :
(gdb) info stack
0 0x4c22cb94 in raise () from /lib/libc.so.6
1 0x4c230670 in abort () from /lib/libc.so.6
2 0xb6e9e6c4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
3 0xb6e9c214 in ?? () from /usr/lib/libstdc++.so.6
4 0xb6e9c288 in std::terminate() () from /usr/lib/libstdc++.so.6
5 0xb6e9c5ac in __cxa_throw () from /usr/lib/libstdc++.so.6
6 0x0011824c in LocationTest::crashingLocCb (location=<optimized out>)
at ../../../TestLibrary/200-Location/src/locationtest.cpp:427
7 0x00144f64 in locationCb (location=<optimized out>)
at ../../PAL/src/tms/pallocationprovider.cpp:109
8 0xb6fbdb50 in locationcallback_thread (thread_info=0x1a82b8)
at ../lib_c/src-gen/location_proxy.c:273
9 0x4c33defc in ?? () from /lib/libpthread.so.0
What I would like to do now :
I want to catch the signal SIGABRT and resume the test application, to go further (check service has not some internal state broken ; check it has not caused some leak etc.. )
What would be the best approach to have something as clean as possible ?
This is to be done with the signal handler, but then would the other running threads be harmed ? what is the best method then to send back the information caught in the signal handler to the relevant thread ?
(I have yet not much experience with those posix signals)
Here is how I solved my problem (in pseudocode). There were probably other ways, I'm still all ears opened :
void malfunction()
{
terminate_handler previousTerminateHandler = set_terminate(callbackUnhandledExceptionTerminateHandler);
registerCallback(throwingCb);
launchTheTest();
waitForErrorEvent();
saveTheResult();
doSomeCleanUp();
set_terminate(previousTerminateHandler);
return;
}
static void callbackUnhandledExceptionTerminateHandler()
{
try{ throw; }
catch(const exception& e) {
cout << e.what() << endl;
notifyTheErrorEvent();
}catch(...){
cout << "callbackUnhandledExceptionTerminateHandler : else ???" << endl;
abort();
}
//Log whatever information, you need such as pid, stack or whatever
cout << "processId = " << getpid() << endl;
//Here if you return from this handler, it will call abort();
//You could let it ends, if you already logged what you needed.
//You could also trap the thread, if this is something you already do elsewhere before stopping the application.
}
In my case, I could check the service would be resilient to a crash of the customer application, and still be able to let other (or even the same!) open another proxy and do more work. Now left to do is to make sure no memory leak is caused here. (only to answer to whom would question why all this).
In a more general case, this same handling could be used to print the stack upon unhandled exception, without the need of gdb.