Обработчик сигнала возвращается к инструкции, которая его сработала, а именно *a = 5
, которая вызывает его зацикливание.
У вас есть несколько проблем, включая использование printf
внутри обработчика сигнала.
Есть безопасные и небезопасные способы борьбы с этим
ПРИМЕЧАНИЯ
Использование signal(2)
не рекомендуется для обработки сигналов в целом.
Обработка SIGSEGV
еще сложнее из-за того, как работает семантика сигнала. Цитата из справочной страницы:
Единственное переносимое использование signal () - установить расположение сигнала в SIG_DFL или SIG_IGN. Семантика при использовании signal ()
установить обработчик сигнала варьируются по
системы (и POSIX.1 явно разрешает эту вариацию); не используйте его для этой цели.
POSIX.1 решил проблему переносимости, указав sigaction (2), который обеспечивает явный контроль семантики, когда
вызывается обработчик сигнала; используйте этот интерфейс вместо signal ().
Итак, первое, что вы должны сделать, это использовать sigaction
.
Далее, обработка SIGSEGV - странный зверь:
Как написать обработчик сигнала для перехвата SIGSEGV?
и
Позволяет ли linux выполнять какие-либо системные вызовы из обработчиков сигналов?
иметь хорошие ответы и вдаваться в конкретные детали. В некоторых ответах есть внешние ссылки.
Как это сделать с помощью сигнала (2)
Хорошо :-) Допустим, вы хотите использовать сигнал (2) и вы хотите поиграть с этим странным образом ....
Вы можете использовать sigjmpset
и siglongjmp
.
sigjmpset
отмечает точку, к которой siglongjmp
должен перейти. При первом вызове sigjmpset
(для установки точки) возвращается 0. Когда к нему переходит siglongjmp
(что означает, что в результате длинного прыжка он вызывается снова), возвращается 1.
Что означает, что мы можем сделать это:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
sigjmp_buf env;
int sigsav;
void sighandler(int signum)
{
const char msg[] = "Skipping signal\n";
write(2, msg, sizeof(msg));
siglongjmp(env, sigsav);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
if(!sigsetjmp(env, sigsav)) {
printf("setting value of a\n");
*a = 5;
}
else {
printf("returned to sigsetjmp, but now we skip it!\n");
}
return 0;
}