Exception not caught after signal

痴心易碎 提交于 2020-01-16 08:20:30

问题


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.


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/52539331/exception-not-caught-after-signal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!