Почему я получаю непрерывный SIGSEGV в коде ниже C - PullRequest
0 голосов
/ 07 июля 2019

Я пытаюсь выучить сигналы. Я знаю, что недопустимый доступ к памяти приведет к segfault. Итак, я регистрирую обработчик сигнала для сигнала SIGSEGV.

#include <stdio.h>
#include <signal.h>


void sighandler(int signum)
{
    printf("%s\n", __func__);
}

int main()
{
    int *a = NULL;
    signal(SIGSEGV, sighandler);
    *a = 5;
    return 0;
}

Запустив этот код, я постоянно получаю сигналы SIGSEGV. Я думал, что должен получить сигнал только один раз. Не могли бы вы, ребята, объяснить, почему я постоянно получаю сигналы

Ответы [ 2 ]

4 голосов
/ 07 июля 2019

После того, как обработчик SEGV завершает работу, запускаемая команда повторяется.Поскольку вы не сделали ничего, чтобы предотвратить сбой следующего выполнения, вы снова получаете SEGV до бесконечности.

Подробнее см. В этот ответ .

2 голосов
/ 07 июля 2019

Обработчик сигнала возвращается к инструкции, которая его сработала, а именно *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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...