Ответ 1
Если вы хотите узнать причину, вы можете зарегистрировать обработчик сигнала, например:
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: либо страница, к которой вы обращались, не была отображена вообще, либо вам не разрешалось выполнять любую операцию, которую вы пытались выполнить на этой странице.
Здесь, после срабатывания обработчика сигнала, он отменяет регистрацию и заменяет действие по умолчанию. Это приводит к тому, что операция не выполняется снова, поэтому ее можно поймать обычным маршрутом. Это нормальное поведение ошибки страницы (предшественник для получения seg-сбоя), так что такие вещи, как работа с поисковым вызовом, работают.