关于在醒目多线程环境中SIGSEGV [英] About catching the SIGSEGV in multithreaded environment

查看:308
本文介绍了关于在醒目多线程环境中SIGSEGV的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有可能/推荐的办法赶上在多线程环境中的SIGSEGV信号。我在处理由类似提出的SIGSEGV特别感兴趣*((INT *)0)= 0。

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'.

有关此主题的一些阅读使我signal()和sigaction的(),它安装一个信号处理程序。虽然没有似乎多线程环境看好。然后,我尝试了sigwaitinfo(),接收信号在一个线程中使用事先pthread_sigmask()调用,阻止对其他信号。它致力于在其信号SIGSEGV引发的程度,用养(),线程内部或当它是由像发送到进程杀-SIGSEGV';然而,*(为(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\n");
                exit(EXIT_FAILURE);
        }
    }

void *buggy_thread(void *param)
{
        char *ptr = NULL;
        block_signal();                                                                                                 

        printf("Thread %lu created\n", pthread_self());

        // Sleep for some random time   
        { ... }

        printf("About to raise from %lu\n", 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\n");
                else
                        printf("Received signal SIGSEGV from %u\n", 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\n");
                exit(EXIT_FAILURE);
        }

        for (i = 0; i < 10; ++i) {
                if (pthread_create(&tid, NULL, buggy_thread, NULL) {
                        fprintf(stderr, "Cannot create thread\n");
                        exit(EXIT_FAILURE);
                }
        }

        pause();
}

没想到,程序段故障去世打印募集的线程ID代替。

Unexpectedly, the program dies with a segmentation fault instead of printing the raiser's thread id.

推荐答案

您code不调用的的sigaction(2),我相信它应该调用它。阅读也信号(7)。和信号作用(直通 sa_sigaction 字段应该做的东西(机专用)的 siginfo_t 来跳过问题的机器指令,或 MMAP 违规地址,或从信号处理程序返回你会得到的时候调用 siglongjmp ,否则 SIGSEGV 再次因为违规的机器指令重新启动。

Your code does not call sigaction(2), and I believe it should call it. Read also signal(7). And the signal action (thru sa_sigaction field should do something (machine specific) with its siginfo_t to skip the offending machine instruction, or to mmap the offending address, or call siglongjmp, otherwise when returning from the signal handler you'll get the SIGSEGV again since the offending machine instruction is restarted.

您不能在另一个线程处理 SIGSEGV ,由于异步信号是线程特定的(见的这个答案),所以你尝试用来实现sigwaitinfo 不能工作。特别 SIGSEGV 被定向到违例线程

You cannot handle the SIGSEGV in another thread, since asynchronous signals are thread specific (see this answer), so what you try to achieve with sigwaitinfo cannot work. In particular SIGSEGV is directed to the offending thread.

阅读也所有关于Linux信号的。

这篇关于关于在醒目多线程环境中SIGSEGV的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆