cannot catch segmentation fault second time - c++

I'm trying to restart the program when segmention fault occures.
I have following minimal reproducible code:-
#include <csignal>
#include <unistd.h>
#include <iostream>
int app();
void ouch(int sig) {
std::cout << "got signal " << sig << std::endl;
exit(app());
}
struct L { int l; };
static int i = 0;
int app() {
L *l= nullptr;
while(1) {
std::cout << ++i << std::endl;
sleep(1);
std::cout << l->l << std::endl; //crash
std::cout << "Ok" << std::endl;
}
}
int main() {
struct sigaction act;
act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGKILL, &act, 0);
sigaction(SIGSEGV, &act, 0);
return app();
}
It successfully catches sigsegv first time but after it prints 2, it shows me segmentation fault (core dumped)
1
got signal 11
2
zsh: segmentation fault (core dumped) ./a.out
tested with clang 12.0.1 and gcc 11.1.0 on ArchLinux
Is this operating system specific behavior or is something wrong in my code

The problem is that when you restart the program by calling exit(app()) from inside ouch(), you are still technically inside the signal handler. The signal handler is blocked until you return from it. Since you never return, you therefore cannot catch a second SIGSEGV.
If you got a SIGSEGV, then something really bad has happened, and there is no guarantee that you can just "restart" the process by calling app() again.
The best solution to handle this is to have another program start your program, and restart it if it crashed. See this ServerFault question for some suggestions of how to handle this.

Related

Why is CLion not showing exceptions?

CLion appears to be not showing me any exceptions when running my code. To test this, I've created a new project with only the following code:
#include <iostream>
int main() {
std::cout << "--- One" << std::endl;
throw 6;
std::cout << "--- Two" << std::endl;
return 0;
}
Which leads to the following output:
C:\Users\david\CLionProjects\untitled\cmake-build-debug\untitled.exe
--- One
Process finished with exit code 0
As you can see, code before the exception is executed and code following it is not executed (as you would expect). But instead of a message about the exception, it says "Process finished with exit code 0", as if no exception had occurred.
The same code compiled and executed on Ubuntu (via terminal) displayed an error message. So I assume the problem is with CLion.
How can I resolve this problem so that I can see messages for exceptions in my code?
Is there any setting that could lead to such behaviour?
I'm using CLion on Windows 10 with Cygwin. Here's a screenshot of the problem:
Throw requires also try and catch
From:
http://www.cplusplus.com/doc/tutorial/exceptions/
// exceptions
#include <iostream>
using namespace std;
int main () {
try
{
throw 20;
}
catch (int e)
{
cout << "An exception occurred. Exception Nr. " << e << '\n';
}
return 0;
}
that compiled and run under cygwin shows:
$ g++ prova1.cc -o prova1
$ ./prova1
An exception occurred. Exception Nr. 2

Invoking raise(signal) terminates c++ program

I have two program running on my Raspberry Pi. One interfaces with a user, the other listens for messages and updates a message file when directed. I want the other to signal to the first that the messages have been updated so the first can reload the message file. I though a SIGUSR1 signal would do what I need. However, when I raise the signal, it terminates my program, which still needs to continue listening for new messages. I therefore constructed the test case program "test_raise.cpp":
#include <iostream>
#include <csignal>
int main(){
std::cout << "Ready to raise SIGUSR1." << std::endl;
std::raise(SIGUSR1);
std::cout << "SIGUSR1 has been raised." << std::endl;
}
I am using this compiler:
gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
which generates the following output
pi#raspberrypi:~$./test_raise
Ready to raise SIGUSR1.
User defined signal 1
pi#raspberrypi:~$
Note that the 2nd text output is not produced. None of the documentation I have looked at indicates that raise terminates the issuing program. (Have I missed something?)
Is this a normal function of raise? Is there a way to do signals without terminating the program? What is my better alternative?
Thanks...
Based on a response, I have a program (invoked prior to the raise program) which has a handler for the USR1 signal:
#include <iostream>
#include <csignal>
#include <unistd.h>
bool flag;
void signalHandler( int signum ) {
std::cout << "Interrupt signal (" << signum
<< ") received." << std::endl;
flag = true;
exit(signum);
}
int main () {
signal(SIGUSR1, signalHandler);
flag = false;
while(1) {
std::cout << "Sleeping...." << std::endl;
if (flag){
std::cout << "SIGUSR1 reception noted by main. "
<< std::endl;
flag = false;
}
sleep(1000*1000); // sleep 1 second
}
return 0;
}
Now there is a handler, but the messages was never received and the raise program still terminates prior to the final message. What am I missing here?
If you haven't installed a signal handler to catch and deal with SIGUSR1 then the default behaviour is to terminate the process.
If you intend to handle the signal, then install an appropriate signal handler and do what you need to do to handle the signal. (Remember that there are very few things you are allowed to do in a signal handler).

Is std::uncaught_exceptions useful for avoiding all exceptions? [duplicate]

This question already has answers here:
How to catch segmentation fault in Linux?
(5 answers)
Catching access violation exceptions?
(8 answers)
Closed 6 years ago.
I need to catch segmentation fault and other unknown exceptions in my application. But I do not know how I can do that!
Can I use std::uncaught_exceptions for this aim?
Can I use std::uncaught_exceptions for this aim?
Consider this code:
int main(int argc, char* argv[])
{
int *val = NULL;
*val = 1;
std::cout << "uncaught: " << std::uncaught_exceptions() << std::endl;
return 0;
}
This will likely cause a segmentation fault and nothing will be output.
I need to catch segmentation fault and other unknown exceptions in my application. But I do not know how I can do that!
Exception handling in C++ can be done through the try-catch block, and you could use the std::signal function to catch certain errors like SIGSEGV, SIGFPE, or SIGILL, example:
#include <iostream>
#include <exception>
#include <csignal>
#include <cstdio>
extern "C" {
void sig_fn(int sig)
{
printf("signal: %d\n", sig);
std::exit(-1);
}
}
int main(int argc, char* argv[])
{
int *val = NULL;
std::signal(SIGSEGV, sig_fn);
try {
*val = 1;
} catch (...) {
std::cout << "..." << std::endl;
}
if (std::uncaught_exception()) {
std::cout << "uncaught" << std::endl;
}
std::cout << "return" << std::endl;
return 0;
}
But you should note that this type of exception handling is really meant to do clean-up and shutdown, not necessarily catch and release; take this code for example:
#include <iostream>
#include <exception>
#include <csignal>
#include <cstdio>
extern "C" {
void sig_fn(int sig)
{
printf("signal: %d\n", sig);
}
}
int main(int argc, char* argv[])
{
int *val = NULL;
std::signal(SIGSEGV, sig_fn);
while (true) {
try {
*val = 1;
} catch (...) {
std::cout << "..." << std::endl;
}
}
if (std::uncaught_exception()) {
std::cout << "uncaught" << std::endl;
}
std::cout << "return" << std::endl;
return 0;
}
This code will cause and catch the segmentation fault forever!
If you are trying to catch a segmentation fault, you need to investigate why the segmentation fault (or any error for that matter) happened in the first place and correct that issue; using the above code as an example:
int *val = NULL;
if (val == NULL) {
std::cout << "Handle the null!" << std::endl;
} else {
*val = 1;
}
For further reading: here is a SO Q&A on what a segfault is, as well, here is the Wiki on it, and MIT has some tips on handling and debugging segfaults too.
Hope that can help.

`signal` function on CentOS: unexpected behavior

I need to disable SIGPIPE on CentOS application, because this signal crashes my application when it works with unstable Internet connection.
I use following code in main function:
signal(SIGPIPE, SIG_IGN);
However, program still crashes with SIGPIPE. What is the reason? Have I to call this function on each thread, or it is enough to call in main function, and program will ignore SIGPIPE globally? And if it is not required to be called on each thread, why SIGPIPE still crashes program if it is supposed to ignore the signal?
Here it is a code sample that let you set up your own signal handler on linux, catch SIGPIPE and do something with that.
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <system_error>
#include <iostream>
static sigset_t theMask;
static int count = 0;
static void
signalWrapper(
int theSignalNumber,
siginfo_t* theSignalDescription,
void* theUserContext)
{
// Do something here as reaction to you SIGPIPE
// This is better way to react on such things
std::cout << "Got signal " << theSignalNumber << std::endl;
// Reinstall handler
struct ::sigaction sa;
sa.sa_sigaction = &signalWrapper;
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
try
{
if (::sigaction(theSignalNumber, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
count++;
}
void
setupSignalHandlers()
{
struct ::sigaction sa;
// Prepare mask
sigemptyset(&theMask);
sigaddset(&theMask, SIGPIPE);
// Add some more if you need it to process
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &signalWrapper;
// Perform setup
try
{
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
}
int
main()
{
std::cout << "Set handler!" << std::endl;
setupSignalHandlers();
std::cout << "Emit 5 SIGPIPE signals" << std::endl;
while (count < 5)
{
kill(getpid(), SIGPIPE);
usleep(100);
}
return 0;
}
and output:
Set handler!
Emit 5 SIGPIPE signals
Got signal 13
Got signal 13
Got signal 13
Got signal 13
Got signal 13
I provide signal handler since it is more correct to process signal that breaks your application than ignore it. Perhaps you need to reestablish connection or do some other stuff.
According to the man page for Signal(2), "The Effects of signal() in a multithreaded process are unspecified." You might try making sure to call signal() in the main thread before creating any other threads, but it's not guaranteed to work.
In any case signal() is deprecated, so I would suggest switching to sigaction(). I use it in multithreaded applications all the time without any problems.

How to Handle SIGABRT signal?

Here is the code on which I set my handler for SIGABRT signal then I call abort() but handler does not get trigered, instead program gets aborted, why?
#include <iostream>
#include <csignal>
using namespace std;
void Triger(int x)
{
cout << "Function triger" << endl;
}
int main()
{
signal(SIGABRT, Triger);
abort();
cin.ignore();
return 0;
}
PROGRAM OUTPUT:
As others have said, you cannot have abort() return and allow execution to continue normally. What you can do however is protect a piece of code that might call abort by a structure akin to a try catch. Execution of the code will be aborted but the rest of the program can continue. Here is a demo:
#include <csetjmp>
#include <csignal>
#include <cstdlib>
#include <iostream>
jmp_buf env;
void on_sigabrt (int signum)
{
signal (signum, SIG_DFL);
longjmp (env, 1);
}
void try_and_catch_abort (void (*func)(void))
{
if (setjmp (env) == 0) {
signal(SIGABRT, &on_sigabrt);
(*func)();
signal (SIGABRT, SIG_DFL);
}
else {
std::cout << "aborted\n";
}
}
void do_stuff_aborted ()
{
std::cout << "step 1\n";
abort();
std::cout << "step 2\n";
}
void do_stuff ()
{
std::cout << "step 1\n";
std::cout << "step 2\n";
}
int main()
{
try_and_catch_abort (&do_stuff_aborted);
try_and_catch_abort (&do_stuff);
}
Although you can replace handler for SIGABRT and abort() will pay attention to the handler, the abort is only inhibited if the signal handler does not return. The relevant quote in C99 is in 7.20.4.1 paragraph 2:
The abort function causes abnormal program termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return. ...
Your signal handler does return and thus the program is aborted.
You get those symptoms i.e. the popup debug dialog, when you have a debug build (with windows and Visual Studio- I'm testing with 2012 version), since it sets a debug break, in the debug implementation of abort() ).
If you pick "ignore" you get that message "Function triger"
If you do a release build, then you don't get the debug popup dialog, and you get the message, as expected