Is it possible to capture a segfault with try / catch?

1

To check if it is possible I did the following:

try
{
    int *x = 0;
    *x = 1234;
}
catch(...)
{
    cout << "OK";
}

But when I run it, I get a segfault in the same way. I've read in some sites that try / catch can not capture a segfault, but I do not know if it's true, someone could confirm that.

    
asked by cheroky 20.10.2016 в 04:20
source

2 answers

2

In any language, exceptions are not generated spontaneously, but it is the code itself that is responsible for launching them.

Thus, for example, new throws an exception when the requested reservation can not be made. Simplifying enough, this would be a possible implementation example of new :

int* new(unsigned int numElementos)
{
  int* ptr = (int*)malloc(sizeof(int)*numElementos);
  if(ptr == nullptr)
    throw std::bad_alloc();

  return ptr;
}

In the case of the example that you have set, access to an uninitialized pointer does not call any element of the standard library that can generate exceptions. Here comes into play the Operating System. Modern Operating Systems are able to monitor access to memory and throw errors when trying to access memory for which there is no access. Because the responsibility to cause a failure lies in the Operating System, the solution to be applied to control these accesses is dependent on the Operating System on which the application will run.

  • As a general rule, in Windows this type of errors can be captured using __try and __except . More information here
  • In Linux the error can be captured by listening to the SIGSEV signal. A possible solution in this case, with the idea of managing exceptions, is to capture the signal and launch the corresponding exception:

Windows Example:

#include <iostream>
#include <windows.h> 
#include <excpt.h>

int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
   if (code == EXCEPTION_ACCESS_VIOLATION)
      return EXCEPTION_EXECUTE_HANDLER;

   return EXCEPTION_CONTINUE_SEARCH;
}

int main()
{
   int* ptr = 0;

   __try
   {
     *ptr = 10;
   }
   __except(filter(GetExceptionCode(), GetExceptionInformation()))
   {
     std::cout << "Access Violation\n";
   }
}

Example of SIGSEV:

class SigSevException : public std::exception
{
public:
  SigSevException () noexcept
   : std::exception()
     m_what("Segmentation Fault")
  {}

  SigSevException (const SigSevException &) noexcept = default;

  SigSevException& operator= (const SigSevException &) noexcept = default;

  virtual ~SigSevException() = default;

  const char* what() const noexcept override
  {
    return m_what.c_str();
  }

private:

  std::string m_what;
};

void SignalSIGSEV(int signal)
{
  std::cerr << "señal SIGSEV lanzada";
  throw SigSevException();
}

int main()
{
  signal(SIGSEGV , SignalHandler);

  try
  {
    int* ptr;
    *ptr = 85;
  }

  catch(const std::exception& exc)
  {
    std::cout << exc.what();
  }
}

Greetings.

    
answered by 20.10.2016 / 09:05
source
1

No, a segmentation fault is a signal, not an exception. The exceptions are manually launched by the program (either you, or a library), while the signals are generated by the operating system ( SIGSEGV , SIGABRT , SIGKILL , etc ).

Exceptions are captured with blocks try / catch , and signals with signal handlers .

Signals can not be treated as exceptions because exceptions are thrown in a specific line of the program (where you put throw ), while signals can appear at any time (since they are like interruptions, for example, that the user press Ctrl-C also generates a signal, SIGINT ).

Exception handling involves adding, by the compiler, a certain control code in the final executable for the stack unwinding (the destruction of local objects as the exception traverses functions) and the logical try / catch (the end of the stack unwinding ).

For signals, that control code can not be placed around any particular line of code because the signals are received "from the outside", as if a stone were thrown at you on the roof. They can happen at any time.

Even if you think that a SIGSEGV happens, or is thrown , on the line that accesses an incorrect memory location, it does not really, or does not have to (as far as I know). The signal does not have to be received at the moment that memory is accessed (that is, it does not throw on the line that detects the situation), but it may come with a certain delay, or not never arrive if the memory accessed also belongs to your program (to another object, although in this case you would possibly observe UB - undefined behavior - in execution).

    
answered by 20.10.2016 в 13:24