Reputation: 2023
I try to catch a termination signal to my code to write a restart file before exiting. My solution is based on this answer.
#include <exception>
#include <csignal>
#include <iostream>
class InterruptException : public std::exception
{
public:
InterruptException(int _s) : signal_(_s) { }
int signal() const noexcept
{
return this->signal_;
}
private:
int signal_;
};
/// method to throw exception at signal interrupt
void sig_to_exception(int s)
{
throw InterruptException(s);
}
int main()
{
// activate signal handling
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = sig_to_exception;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
try
{
for (std::size_t i = 0; i < 100000000; ++i)
{
std::cout << i << std::endl;
}
}
catch (const InterruptException& e)
{
std::cout << "Received signal " << e.signal() << std::endl;
std::exit(1);
}
catch(...)
{
std::cout << "Other catch!" << std::endl;
}
}
The exception gets thrown fine, however, my catch block does not catch it. The program terminates with an uncaught exception InterruptException
. I tried with clang and gcc on MacOS. Any idea why the exception is not caught correctly?
Thanks
Output when compiled with g++ 7.3.0:
terminate called after throwing an instance of 'InterruptException'
what(): std::exception
Abort trap: 6
Output when compiled with Apple LLVM 9.0.0
libc++abi.dylib: terminating with uncaught exception of type InterruptException: std::exception
PS: It seems when I compile with Apple LLVM the exception gets caught sometimes, but not all the time, which makes this even weirder.
Upvotes: 0
Views: 617
Reputation: 264699
On most system the stack frame used by the signal handler is not a standard function stack frame as defined by the compiler for function calls.
So throwing out of a sig handler is not supported.
Stack frame for signal handling in the Linux Kernel
From the discussion in the linked question, on a linux system they are not even using the same stack for the stack frame and returning requires jumping back to a system function to restore the original user stack.
Unless the OS is specifically designed to handle exceptions then this is not going to work.
The rule of thumb for signal handlers is to do as little as possible in a signal handler. Set a global flag that can be detected by your normal code then check that flag periodically in your normal code to see when the signal has happened.
Upvotes: 1
Reputation: 76498
There is very little that you can reliably do in a signal handler. In particular, you cannot throw an exception. The code in the question (and the "answer" that it links to) relies, at best, on compiler/OS-specific behavior. For the limits on what you can do in a signal handler, see this.
Note that the link above refers to signal
, which is standard C. sigaction
is not standard C, it's POSIX, and the C++ language definition doesn't impose any requirements on a program that uses it.
Upvotes: 1