A portable way to catch signals and report a problem to the user

If by some miracle segfault occurs in our program, I want to catch SIGSEGV and let the user (possibly the GUI client) know with one return code that a serious problem has occurred. At the same time, I would like to display information on the command line to show which signal was caught.

Today, our signal handler looks like this:

void catchSignal (int reason) { std :: cerr << "Caught a signal: " << reason << std::endl; exit (1); } 

I hear horror screams with the above, as I read from this thread that an evil call does not return a function from the signal handler.

Is there a portable way to process the signal and provide information to users?

EDIT: Or at least portable under POSIX?

+4
source share
4 answers

This table lists all the functions that POSIX guarantees safe protection against asynchronous signal and therefore can be called from the signal handler.

Using the โ€œwriteโ€ command from this table, the following relatively ugly solution will hopefully do the trick:

 #include <csignal> #ifdef _WINDOWS_ #define _exit _Exit #else #include <unistd.h> #endif #define PRINT_SIGNAL(X) case X: \ write (STDERR_FILENO, #X ")\n" , sizeof(#X ")\n")-1); \ break; void catchSignal (int reason) { char s[] = "Caught signal: ("; write (STDERR_FILENO, s, sizeof(s) - 1); switch (reason) { // These are the handlers that we catch PRINT_SIGNAL(SIGUSR1); PRINT_SIGNAL(SIGHUP); PRINT_SIGNAL(SIGINT); PRINT_SIGNAL(SIGQUIT); PRINT_SIGNAL(SIGABRT); PRINT_SIGNAL(SIGILL); PRINT_SIGNAL(SIGFPE); PRINT_SIGNAL(SIGBUS); PRINT_SIGNAL(SIGSEGV); PRINT_SIGNAL(SIGTERM); } _Exit (1); // 'exit' is not async-signal-safe } 

EDIT: Creating windows.

After you try to create this window, it looks like 'STDERR_FILENO' is undefined. From the documentation, however, its meaning looks like "2".

 #include <io.h> #define STDIO_FILENO 2 

EDIT: "exit" should not be called from a signal handler!

As fizzer pointed out , calling _Exit in the above example is a sledgehammer method for signals such as HUP and TERM. Ideally, when these signals are caught, a flag of type volatile sig_atomic_t can be used to notify the main program that it should exit.

The next thing I found useful in my quest.

+12
source

FWIW, 2 is a standard error for Windows, but you will need conditional compilation because their write () is called _write (). You will also want

 #ifdef SIGUSR1 /* or whatever */ 

etc. around all references to signals that are not guaranteed by the definition of standard C.

Also, as noted above, you do not want to handle SIGUSR1, SIGHUP, SIGINT, SIGQUIT and SIGTERM like this.

+1
source

Richard, there is still not enough karma to comment, so I'm afraid a new answer. These are asynchronous signals; you donโ€™t know when they will be delivered, so you may be in library code that needs to be completed in order to remain consistent. Therefore, a signal handler for these signals is required to return the signals. If you call exit (), the library will do some post-main () work, including calling functions registered with atexit () and clearing standard threads. This processing may fail if, say, your signal arrives in a standard library I / O function. Therefore, in C90, you are not allowed to call exit (). Now I see that C99 relaxes the requirement by providing a new _Exit () function in stdlib.h. _Exit () can be safely called from the handler for an asynchronous signal. _Exit () will not call the atexit () functions and may skip cleaning standard threads at the discretion of the implementation.

In bk1e (comment several posts up) The fact that SIGSEGV is synchronous is why you cannot use functions that are not meant to be reentrant. What if the function that crashed held the lock and the function called by the signal handler tries to get the same lock?

This is an opportunity, but it is not a fact that SIGSEGV is synchronous, which is a problem. Calling non-returning functions from a handler is much worse with asynchronous signals for two reasons:

  • asynchronous signal handlers (in general), hoping to return and resume normal program execution. the synchronous signal handler (usually) is about to stop anyway, so you wonโ€™t lose a lot if you crash.
  • in a vicious sense, you have absolute control over the delivery of a synchronous signal - this happens when you execute your defective code and at no other time. During the transmission of the asynchronous signal, you have no control. If the OP's native I / O code is not causing a malfunction - for example, outputting bad char * - its error message has a reasonable chance of success.
+1
source

Write a launcher to run your program and inform the user about the abnormal exit code.

0
source

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


All Articles