I'd like to know if it is possible/the recommended way to catch the SIGSEGV
signal in multithreaded environment. I am particularly interested in handling the SIGSEGV
raised by something like *((int *)0) = 0
.
Some reading on this topic led me to signal()
and sigaction()
, which install a signal handler. While neither seem promising in multithreaded environment. I then tried the sigwaitinfo()
, receiving the signals in one thread with a prior pthread_sigmask()
call that blocks the signal on the others. It worked to the extent upon which the signal SIGSEGV
was raised, using raise(), inside a thread or when it was sent to the process by something like kill -SIGSEGV
; however, *((int*)0) = 0
still kills the process. My test program is as follows
void block_signal()
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGSEGV);
sigprocmask(SIG_BLOCK, &set, NULL);
if (pthread_sigmask(SIG_BLOCK, &set, NULL)) {
fprintf(stderr, "pthread_sigmask failed
");
exit(EXIT_FAILURE);
}
}
void *buggy_thread(void *param)
{
char *ptr = NULL;
block_signal();
printf("Thread %lu created
", pthread_self());
// Sleep for some random time
{ ... }
printf("About to raise from %lu
", pthread_self());
// Raise a SIGSEGV
*ptr = 0;
pthread_exit(NULL);
}
void *dispatcher(void *param)
{
sigset_t set;
siginfo_t info;
int sig;
sigemptyset(&set);
sigaddset(&set, SIGSEGV);
for (;;) {
sig = sigwaitinfo(&set, &info);
if (sig == -1)
fprintf(stderr, "sigwaitinfo failed
");
else
printf("Received signal SIGSEGV from %u
", info.si_pid);
}
}
int main()
{
int i;
pthread_t tid;
pthread_t disp_tid;
block_signal();
if (pthread_create(&disp_tid, NULL, dispatcher, NULL)) {
fprintf(stderr, "Cannot create dispatcher
");
exit(EXIT_FAILURE);
}
for (i = 0; i < 10; ++i) {
if (pthread_create(&tid, NULL, buggy_thread, NULL) {
fprintf(stderr, "Cannot create thread
");
exit(EXIT_FAILURE);
}
}
pause();
}
Unexpectedly, the program dies with a segmentation fault instead of printing the raiser's thread id.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…