Как использовать «sigaltstack» в программе обработки сигналов?

#c #posix #signals

#c #posix #сигналы

Вопрос:

Кто-нибудь знает, как использовать sigaltstack в реальной программе обработки сигналов? Простой, но полный код может оказаться отличным подспорьем!

Комментарии:

1. // , Возможно, для этого потребовалось бы некоторое улучшение форматирования. Вы уже пробовали что-нибудь? У вас это сработало?

Ответ №1:

Вот минимальный пример программы, которая использует sigaltstack для отслеживания бесконечной рекурсии. Если вы закомментируете sigaltstack вызов или SA_ONSTACK флаг, обработчик сигналов не сможет запуститься, потому что у него не осталось стека, и программа просто завершится сбоем.

 #define _XOPEN_SOURCE 700
#include <signal.h>
#include <unistd.h>
void handler(int sig)
{
    write(2, "stack overflown", 15);
    _exit(1);
}
unsigned infinite_recursion(unsigned x) {
    return infinite_recursion(x) 1;
}
int main()
{
    static char stack[SIGSTKSZ];
    stack_t ss = {
        .ss_size = SIGSTKSZ,
        .ss_sp = stack,
    };
    struct sigaction sa = {
        .sa_handler = handler,
        .sa_flags = SA_ONSTACK
    };
    sigaltstack(amp;ss, 0);
    sigfillset(amp;sa.sa_mask);
    sigaction(SIGSEGV, amp;sa, 0);
    infinite_recursion(0);
}
  

На самом деле может быть использовано более сложное использование siglongjmp для перехода из обработчика сигналов обратно в точку, где бесконечной рекурсии можно избежать. Это недопустимо, если используются вызовы библиотеки async-signal-unsafe, или если ваши данные могут быть оставлены в небезопасном / невосстановимом состоянии, но если вы выполняете чисто арифметические вычисления, это может быть допустимо.

Возможно, лучшей задачей для обработчика сигналов было бы выполнение аварийного дампа любых ценных / критических данных, которые еще не были сохранены на диске. Это может быть сложно, если вы не можете вызвать функции, небезопасные для асинхронного сигнала, но обычно это возможно, если вы приложите к этому некоторые усилия.

Комментарии:

1. У меня все работает нормально (после исправления одной опечатки). Кстати, при включенной оптимизации gcc генерирует бесконечный цикл, а не рекурсию для функции, и, таким образом, никогда не переполняет стек. С -O0 обработчик сигналов выполняется, как ожидалось.

2. Я пробовал с -O0, как вы сказали, но это по-прежнему приводит к ошибке синхронизации. Может ли это быть версия gcc?

3. В некоторых системах переполнение стека может выдавать SIGSTKFLT вместо SIGSEGV , поэтому вам может потребоваться обработать оба, чтобы быть «переносимыми».

4. @Hola Soy Edu, Ты установил ss с назначенным списком инициализаторов , как это сделал @R..? В противном случае проблема может заключаться в ss.ss_flags . Оно должно быть нулевым , чтобы установить новый альтернативный стек сигналов . Я предложу редактирование, чтобы подчеркнуть это.

5. @Mawg: Похоже на то. Это было очень давно, хотя,

Ответ №2:

 #define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

static void handler(int signo)
{
    int x;
    if(signo == SIGSEGV)
    {
        printf("Waoh, caught signal %sn",strsignal(signo));
        printf("Top of stack is near p", (void*)amp;x);
    }
    _exit(EXIT_FAILURE);
}

static void overflowStack(int i)
{
    char a[8964];
    printf("(%d) Called overflow function. The top of stack is near pn",i ,amp;a[0]);
    overflowStack(i 1);
}

int main(int argc, char *argv[])
{


    /*(1)specify that the signal handler will be allocated onto the
    alternate signal stack*/
    stack_t sigstack;
    //malloc return the pointer to the allocated memory on success
    //malloc return NULL on error
    sigstack.ss_sp = malloc(SIGSTKSZ);
    if( sigstack.ss_sp == NULL)
    {
        printf("Err: malloc errorn");
        exit(EXIT_FAILURE);
    }
    sigstack.ss_size = SIGSTKSZ;
    sigstack.ss_flags = 0;

    /*(2)Specify that the signal handler will be allocated on the alternate 
    signal stack */
    if(sigaltstack(amp;sigstack, NULL) == -1)
    {
        printf("Err: sigaltstack errorn");
        exit(EXIT_FAILURE);
    }
    // sbrk() change the location of the program break, which defines the end of the process's data segment 
    //On success, sbrk() returns the previous program break. 
    printf("Now the alternate signal stack is successfully allocatedn");
    printf("The address of signal stack is : p - pn",sigstack.ss_sp,(char*)sbrk(0)-1);

    /*(3)define a struct sigaction to deal with the SIGSEGV*/
    struct sigaction act;
    act.sa_flags = SA_ONSTACK;
    sigemptyset(amp;act.sa_mask);
    act.sa_handler = handler;
    sigaction(SIGSEGV, amp;act, NULL);

    overflowStack(1);

}
  

Комментарии:

1. Вывод: Теперь альтернативный стек сигналов успешно выделен, адрес стека сигналов: 0x563078b3c260 — 0x563078b5cfff (1) Вызывается функция переполнения. Вершина стека находится рядом с 0x7ffdad9eed00 (2), вызываемой функцией переполнения. Вершина стека находится рядом с 0x7ffdad9ec9d0 (3), вызываемой функцией переполнения. Вершина стека находится рядом с 0x7ffdad9ea6a0 (929), вызываемой функцией переполнения. Вершина стека находится вблизи 0x7ffdad1f5f00 Waoh, обнаружена ошибка сегментации сигнала