#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, обнаружена ошибка сегментации сигнала