如果您想知道原因,您可以注册一个信号处理程序,例如:
void handler(int signum, siginfo_t *info, void *context)
{
struct sigaction action = {
.sa_handler = SIG_DFL,
.sa_sigaction = NULL,
.sa_mask = 0,
.sa_flags = 0,
.sa_restorer = NULL
};
fprintf(stderr, "Fault address: %p\n", info->si_addr);
switch (info->si_code) {
case SEGV_MAPERR:
fprintf(stderr, "Address not mapped.\n");
break;
case SEGV_ACCERR:
fprintf(stderr, "Access to this address is not allowed.\n");
break;
default:
fprintf(stderr, "Unknown reason.\n");
break;
}
/* unregister and let the default action occur */
sigaction(SIGSEGV, &action, NULL);
}
然后在您需要注册的地方:
struct sigaction action = {
.sa_handler = NULL,
.sa_sigaction = handler,
.sa_mask = 0,
.sa_flags = SA_SIGINFO,
.sa_restorer = NULL
};
if (sigaction(SIGSEGV, &action, NULL) < 0) {
perror("sigaction");
}
基本上,您注册一个在 SIGSEGV 交付时触发的信号,并获得一些附加信息,以引用手册页:
The following values can be placed in si_code for a SIGSEGV signal:
SEGV_MAPERR address not mapped to object
SEGV_ACCERR invalid permissions for mapped object
这些映射到出现段错误的两个基本原因——您访问的页面根本没有映射,或者您不被允许执行您尝试对该页面执行的任何操作。
在信号处理程序触发后,它会自行注销并替换默认操作。这会导致无法再次执行的操作,因此可以被正常路由捕获。这是页面错误的正常行为(出现 seg 错误的前兆),因此请求分页之类的事情可以正常工作。