how to use "sigaltstack" in signal handler program?
Here is a minimal sample program that uses sigaltstack
to catch infinite recursion. If you comment out the sigaltstack
call or SA_ONSTACK
flag, the signal handler will not be able to run because it has no stack left and the program will just crash.
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <unistd.h>
void handler(int sig)
{
write(2, "stack overflow\n", 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(&ss, 0);
sigfillset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, 0);
infinite_recursion(0);
}
A more sophisticated use might actually perform siglongjmp
to jump out of the signal handler and back to a point where the infinite recursion can be avoided. This is not valid if async-signal-unsafe library calls are being used, or if your data might be left in an unsafe/unrecoverable state, but if you're performing pure arithmetic computations, it may be valid.
Perhaps a better task for the signal handler would be performing an emergency dump of any valuable/critical data that wasn't already saved to disk. This could be difficult if you can't call async-signal-unsafe functions, but it's usually possible if you put some effort into it.
#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 %s\n",strsignal(signo));
printf("Top of stack is near %10p", (void*)&x);
}
_exit(EXIT_FAILURE);
}
static void overflowStack(int i)
{
char a[8964];
printf("(%d) Called overflow function. The top of stack is near %10p\n",i ,&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 error\n");
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(&sigstack, NULL) == -1)
{
printf("Err: sigaltstack error\n");
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 allocated\n");
printf("The address of signal stack is : %10p - %10p\n",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(&act.sa_mask);
act.sa_handler = handler;
sigaction(SIGSEGV, &act, NULL);
overflowStack(1);
}