我的系统是ubuntu 12.04。
我从man 2 signalfd
修改了示例,并在exmaple中添加了sigaddset(&mask, SIGSEGV)
。但是在生成SIGSEGV
时我无法获得输出。
这是glibc
的错误吗?源代码的片段如下:
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
sigaddset(&mask, SIGSEGV);
/* Block signals so that they aren't handled
according to their default dispositions */
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
handle_error("sigprocmask");
sfd = signalfd(-1, &mask, 0);
if (sfd == -1)
handle_error("signalfd");
int* a = NULL;
for (;;) {
s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
if (s != sizeof(struct signalfd_siginfo))
handle_error("read");
if (fdsi.ssi_signo == SIGINT) {
printf("Got SIGINT\n");
(*a) = 1;
} else if (fdsi.ssi_signo == SIGQUIT) {
printf("Got SIGQUIT\n");
exit(EXIT_SUCCESS);
} else {
printf("Read unexpected signal\n");
}
}
答案 0 :(得分:4)
有关详细说明,请参阅this和that个答案。仔细阅读signal(7)和signal-safety(7)。另请注意,virtual address space的process对该流程的所有threads都是通用的,并且在该proc(5)之间共享。另请参阅pmap(1)(并使用signalfd(2))并尝试从流程内部阅读/proc/self/maps
以了解其实际虚拟地址空间。
粗略地说,如果你使用sigaction(2)处理(异步)SIGSEGV
(由于内核在发生异常故障后产生),看起来你已经安装了一个"内核"信号处理程序神奇地"写一些文件描述符上的某些字节(你几乎可以通过在某个管道上安装信号处理程序来模仿signalfd
;但signalfd
保证一些&# 34;原子性"你没有赢得其他)。
当您退出处理时,机器处于相同状态,因此SIGSEGV再次发生。
如果您要处理SIGSEGV
,则需要使用siglongjmp(3)或过时的signal(2)
来安装处理例程(因此您无法使用signalfd
SIGSEGV),然后你应该
ucontext_t
指定)更改为由sigaction
安装的处理程序SA_SIGINFO
),例如通过更改某些寄存器或更改地址空间(例如,通过从处理程序内部调用mmap(2))。洞察力是输入SIGSEGV处理程序,程序计数器设置为错误机器指令。当您从SIGSEGV处理程序返回时,寄存器处于给定状态(指针ucontext_t
作为传递给sa_sigaction
的{{1}}函数的第三个参数。如果你没有改变那个状态,那么重新执行相同的机器指令,并且由于你没有改变任何东西,同样的故障发生了,内核再次发送相同的SIGSEGV信号。
BTW,一个很好的软件处理示例,SIGSEGV是Ravenbrook MPS垃圾收集库。他们的写屏障(用GC说法)是通过处理SIGSEGV来实现的。这是非常聪明(和非便携)的代码。
注意:在实践中,如果您只想显示回溯信息,可以从sigaction
处理程序执行此操作(例如,使用GCC libbacktrace或backtrace(3)然后_exit(2) -ing而不是从SIGSEGV
信号处理程序返回;它不完美,不会一直工作 - 例如。如果你corrupted the memory heap - 因为你会调用非异步信号安全函数,但实际上运行得很好。最近的GCC正在这样做(在编译器内部,例如SIGSEGV
及其插件),它有很多帮助。
答案 1 :(得分:2)
您只能阻止kill(2)
和朋友发送的SISGSEGV。来自sigprocmask(2)
的联机帮助页:
如果生成SIGBUS,SIGFPE,SIGILL或SIGSEGV 阻止,结果是未定义的,除非信号是由...生成的 kill(2),sigqueue(3)或raise(3)
由于信号未被sigprocmask
真正阻止 - signalfd
- signalfd
的先决条件不起作用。一种简单的测试方法是使用您的程序,但不是引起真正的分段错误,而是发送kill -11
的信号。