📜 ⬆️ ⬇️

Handling Segmentation Fault in C ++

Introductory


C ++ is an “unmanaged” language, so programs can crash — crash without saving user data, error messages, etc. - it is only necessary, for example, to get into an uninitialized memory. For example:
void fall() { char * s = "short_text"; sprintf(s,"This is very long text"); } 

or
 void fall() { int * pointer = NULL; *pointer = 13; } 


It would be better for everyone if we could “catch” the crash of the program - just like in java we catch exceptions - and perform at least something before the program crashes (save the user's document, display a dialog with an error message and t .P.)

There is no general solution to the problem, since C ++ does not have its own model for handling exceptions related to working with memory. Nevertheless, we will consider two methods that use the features of the operating system that caused the exception.
')


Method 1: SEH


If you use Windows OS as a target OS and Visual C ++ as a compiler, then you can use Structured Exception Handling - an extension of the C ++ language from Microsoft, which allows you to catch any exceptions occurring in the program.

The general syntax for exception handling is as follows:

 __try { segfault1(); } __except( condition1 ) { //  ,  condition1 == EXCEPTION_EXECUTE_HANDLER. //  condition1  ()   ,  //  ,   EXCEPTION_EXECUTE_HANDLER //     ,     } __except( condition2 ) { //    } __finally { // ,          } 


Here is a “working example” - “copy and paste into Visual Studio”
 #include <stdio.h> #include <windows.h> #include <excpt.h> int memento() //  Segfault { MessageBoxA(NULL,"Memento Mori","Exception catched!",NULL); return 0; } void fall() //  segfault { int* p = 0x00000000; *p = 13; } int main(int argc, char *argv[]) { __try { fall(); } __except (EXCEPTION_EXECUTE_HANDLER) { memento(); } } 


I personally could not get to earn __finally (that's why I wrote __except with verification code, which always works), but this is probably the curvature of my hands.

This technique, for all its attractiveness, has a number of disadvantages:



There were so many minuses that you have to look for a second solution.

Method 2: POSIX Signals



The method is designed for the fact that at the time of the crash the program receives a POSIX SIGSEGV message. This is certainly true in all UNIX systems, but this is in fact the case (although no one guaranteed, windows is not posix-compatible) in windows too.

The technique is simple - we have to write a SIGSEGV message handler, in which the program will perform “farewell actions” and, finally, will fall:
 void posix_death_signal(int signum) { memento(); //   signal(signum, SIG_DFL); //   exit(3); //  .    ,     . } 

after which we must register this handler:
 signal(SIGSEGV, posix_death_signal); 


Here is a finished example:
 #include <stdio.h> #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <signal.h> int memento() { int a=0; MessageBoxA(NULL,"Memento mori","POSIX Signal",NULL); return 0; } void fall() { int* p = 0x00000000; *p = 13; } void posix_death_signal(int signum) { memento(); signal(signum, SIG_DFL); exit(3); } int main(int argc, char *argv[]) { signal(SIGSEGV, posix_death_signal); fall(); } 


Unlike SEH, it always works: the solution is “multi-threaded” (you can drop the program in any thread, the handler will run anyway) and “cross-platform” - it works under any compiler, and under any POSIX-compatible OS.

Source: https://habr.com/ru/post/131412/


All Articles