Ваш код игнорирует SIGSEGV, а не перехватывает его. Напомним, что команда, которая вызвала сигнал, перезапускается после обработки сигнала. В вашем случае обработка сигнала ничего не изменила, так что в следующий раз, когда пробуете оскорбительную инструкцию, она тоже не справится.
Если вы собираетесь поймать сигнал, измените это
signal(SIGSEGV, SIG_IGN);
к этому
signal(SIGSEGV, sighandler);
Вы, вероятно, должны также использовать sigaction()
вместо signal()
. Смотрите соответствующие справочные страницы.
В вашем случае нарушающая инструкция пытается разыменовать нулевой указатель.
printf("%d", *p);
То, что следует, полностью зависит от вашей платформы.
Вы можете использовать gdb
, чтобы установить, какая конкретная инструкция по сборке запускает сигнал. Если ваша платформа похожа на мою, вы найдете инструкцию
movl (%rax), %esi
с регистром rax, имеющим значение 0, т.е. NULL
. Один (непереносимый!) Способ исправить это в вашем обработчике сигналов - использовать третий аргумент сигнала, который получает ваш обработчик, то есть пользовательский контекст. Вот пример:
#include <signal.h>
#include <stdio.h>
#define __USE_GNU
#include <ucontext.h>
int *p = NULL;
int n = 100;
void sighandler(int signo, siginfo_t *si, ucontext_t* context)
{
printf("Handler executed for signal %d\n", signo);
context->uc_mcontext.gregs[REG_RAX] = &n;
}
int main(int argc,char ** argv)
{
signal(SIGSEGV, sighandler);
printf("%d\n", *p); // ... movl (%rax), %esi ...
return 0;
}
Эта программа отображает:
Handler executed for signal 11
100
Сначала он запускает обработчик, пытаясь разыменовать NULL-адрес. Затем обработчик устраняет проблему, устанавливая rax по адресу переменной n
. Как только обработчик возвращается, система повторяет ошибочную инструкцию, и это время успешно выполняется. printf()
получает 100 в качестве второго аргумента.
Я настоятельно рекомендую не использовать такие непереносимые решения в своих программах.