#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void sigfunc(int sig) {
printf("recv a signal %d\n", sig);
abort();
}
int main(void) {
signal(SIGSEGV, sigfunc);
char sz[10] = {0};
printf("cpy begin 111111111\n");
strcpy(sz, "hello liwq, hello liwq, hello liwq");
printf("cpy end 2222222\n");
printf("pid %d\n", getpid());
printf("ok 1111111111\n");
sleep(3);
printf("ok 2222222222\n");
sleep(500);
printf("ok 3333333333\n");
return 0;
}
不知道是和系统有关系么?在我的机器上运行到结束以后才会处理内存越界的信号。
信号是在内核态向用户态切换前处理的吧,那这段代码就没有切换到内核态运行过么,sleep了这么久,就一直占用CPU,没有被调度过么?请大神们帮解答一下!!!
这是很正常的行为呀,看汇编(x86_64)(希望没弄错什么):
所以直到 main 函数返回时才会发生内存访问违例,导致 SIGSEGV 信号的发送。硬件才不在乎你的访问有没有越界呢,它只关心你有没有权限访问指定的内存地址。
另外,严格来讲,在信号处理函数里是不能调用 printf 等会导致内存分配的函数的,因为信号处理是异步的,你需要假设它在任意时候都可能被执行。如果你的程序正好在执行 malloc 之类的函数,锁住了 C 标准库的内存分配用的数据结构,你再次使用需要这个锁的函数就会导致死锁。所以信号处理函数中只能调用可重入函数。
又,你要处理 SIGSEGV 信号通常得使用另外分配的栈来处理,因为已有的函数栈已经坏掉不能用了。当然很少会有程序去费心思处理 SIGSEGV 的,最多记录一些日志而已。