2

I am receiving segmentation fault in random time.
I registered the signal but signal handler not called when segmentation fault occurred

#include <unistd.h>
#include <dlfcn.h>
#include <iostream>
#include <signal.h>
#include <execinfo.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

using namespace std;

void  Handler(int sig)
{
     cout << "handler called " << strsignal(sig) << endl;
     exit(1);
}


int main()
{
    cout << "Testing crash !" << endl;

    signal(SIGSEGV, Handler);
    signal(SIGINT, Handler);
    signal(SIGABRT, Handler);
    for (int i = 0; i < 10; i++)
    {
        cout << i << " Before open" << endl;
        void *handler = dlopen("/home/user/Test.so", RTLD_LAZY);
        if (handler)
        {
            cout << i << " Before close" << endl;
            dlclose(handler);
            cout << i << " After close" << endl;
        }
        else
        {
            cout << "Error " << dlerror() << endl;
        }
    }

    return 0;
}

Output:
Run1

Testing crash !
0 Before open
0 Before close
0 After close
1 Before open
1 Before close
Segmentation fault (core dumped)

Run2

0 Before open
0 Before close
0 After close
1 Before open
1 Before close
1 After close
Segmentation fault (core dumped)

Problem is signal handler is not called to analyze the problem

Bhavith C
  • 72
  • 5
  • 1
    Segmentation fault is SIGSEGV. SIGINT is triggered when you press Ctrl-C. – Paul Stelian Apr 19 '17 at 05:13
  • And btw, there is the raise() system call, using kill may just be nondeterministic if kernel is buggy? – Paul Stelian Apr 19 '17 at 05:14
  • @PaulStelian. I have tried removing the thing you mentioned even then I am getting same result. If you want I will paste the updated code – Bhavith C Apr 19 '17 at 05:17
  • It's just you are replacing the handler for the wrong signal. You should replace SIGSEGV and perhaps SIGABRT too. – Paul Stelian Apr 19 '17 at 05:18
  • Oh I see... Then I wonder how one can ask the shell itself for the signal – Paul Stelian Apr 19 '17 at 05:19
  • Why do you do this `kill(getpid(), signum);` in a signal handler? IMO, this creates an infinite loop... – Arash Apr 19 '17 at 05:20
  • @PaulStelian, Sorry I did not get you. I have updated the source and tested again but still same thing happening. Where do I need to replace SIGDEGV and SIGABRT – Bhavith C Apr 19 '17 at 05:21
  • 1
    Beware of printf buffering behavior; you should not use printf when code is crashing. Or if you do, please also call fflush(stdout). – Paul Stelian Apr 19 '17 at 05:21
  • @Arash. Now I updated the source . I was using Kill because to handle signal and to generate the coredump – Bhavith C Apr 19 '17 at 05:22
  • The signal handler should cause the code to stop somehow. Perhaps _exit(1)? Or `raise(SIGKILL)`? – Paul Stelian Apr 19 '17 at 05:23
  • 3
    @PaulStelian printf/fflush all are not [async safe functions](http://man7.org/linux/man-pages/man7/signal-safety.7.html) and should not be used at all in signal handlers! – Aconcagua Apr 19 '17 at 05:24
  • @Aconcagua Indeed, I just said what would be semi-ok in his case (if he does this he at least should flush). Maybe using raw blockwrites would be nicer. – Paul Stelian Apr 19 '17 at 05:25
  • 1
    [How to write a signal handler to catch SIGSEGV?](http://stackoverflow.com/questions/2663456/how-to-write-a-signal-handler-to-catch-sigsegv) – Arash Apr 19 '17 at 05:28
  • Hi Guys I have updated the source with simple handler and removed unnecessary code. Please review it now. Still I am getting same errors – Bhavith C Apr 19 '17 at 05:33
  • @BhavithC Have you tried to create the seg fault by simpler means? Such as `int* n = NULL; printf("%d", *n);` – Aconcagua Apr 19 '17 at 05:47
  • @Aconcagua. I tried its working fine – Bhavith C Apr 19 '17 at 06:26
  • 1
    Strange is the second run. The segmentation fault seems to appear within your own code - but that could be a buffering problem. I recommend to add `<< std::flush` to every output at the end to exclude this possibility. And then I would attach a debugger to at least see *where* the segmentation fault occurs. That might give additional hints. I personally tried to produce kind of endless loop re-creating the seg fault *within the signal handler* - but I apparently did not get a second signal then. – Aconcagua Apr 19 '17 at 06:45
  • 1
    @Aconcagua Thank you very much for your hint. As you said if I run the same code for my own library then there is no issue, It is only happening with some library. My expectation is what ever the wrong code exist in library. my dlopen and dlclose should open and close with out seg fault. I will try what you said thanks for response – Bhavith C Apr 19 '17 at 09:06

1 Answers1

2

Problem is signal handler is not called to analyze the problem

Your signal handler likely is called. But it likely deadlocks as it's not async-signal-safe. Per POSIX:

the behavior is undefined ... if the signal handler calls any function defined in this standard other than one of the functions listed in the following table.

This code calls async-signal unsafe functions, and therefore invokes undefined behavior:

void  Handler(int sig)
{
     cout << "handler called " << strsignal(sig) << endl;
     exit(1);
}

Only async-signal-safe functions can be called from within a signal handler.

Neither exit() nor any use of C++ streams of any type are async-signal-safe.

Per POSIX, the list of async-signal-safe functions are:

_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execl()
execle()
execv()
execve()
faccessat()
fchdir()
fchmod()
fchmodat()
fchown()
fchownat()
fcntl()
fdatasync()
fexecve()
ffs()
fork()
fstat()
fstatat()
fsync()
ftruncate()
futimens()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
htonl()
htons()
kill()
link()
linkat()
listen()
longjmp()
lseek()
lstat()
memccpy()
memchr()
memcmp()
memcpy()
memmove()
memset()
mkdir()
mkdirat()
mkfifo()
mkfifoat()
mknod()
mknodat()
ntohl()
ntohs()
open()
openat()
pause()
pipe()
poll()
posix_trace_event()
pselect()
pthread_kill()
pthread_self()
pthread_sigmask()
raise()
read()
readlink()
readlinkat()
recv()
recvfrom()
recvmsg()
rename()
renameat()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
siglongjmp()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sleep()
sockatmark()
socket()
socketpair()
stat()
stpcpy()
stpncpy()
strcat()
strchr()
strcmp()
strcpy()
strcspn()
strlen()
strncat()
strncmp()
strncpy()
strnlen()
strpbrk()
strrchr()
strspn()
strstr()
strtok_r()
symlink()
symlinkat()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
unlinkat()
utime()
utimensat()
utimes()
wait()
waitpid()
wcpcpy()
wcpncpy()
wcscat()
wcschr()
wcscmp()
wcscpy()
wcscspn()
wcslen()
wcsncat()
wcsncmp()
wcsncpy()
wcsnlen()
wcspbrk()
wcsrchr()
wcsspn()
wcsstr()
wcstok()
wmemchr()
wmemcmp()
wmemcpy()
wmemmove()
wmemset()
write()

Note that Linux is not POSIX-compliant here. On Linux, fork() is broken and is not async-signal-safe.

Community
  • 1
  • 1
Andrew Henle
  • 32,625
  • 3
  • 24
  • 56