alternate stacks for signal handlers

Henry Cejtin henry@sourcelight.com
Fri, 21 Jul 2000 20:25:19 -0500


Ok, here is the story with signal stacks.

First,  you  must  allocate a chunk of memory to be used as the signal stack.
It's size must be at least MINSIGSTKSZ, and really should be atleast SIGSTKSG
(these  are defined by including signal.h, and the latter is 8K).  (Actually,
I would make it 2 or 3 times that just to be safe  against  multiple  signals
coming  in really fast.)  Note, for protection against overflowing the signal
stack (not really a problem for us, but we should be safe) you should use the
mmap trick to surround it with regions mapped with no permissions.  Note, the
Intel stack grows by decreasing, so the most important boundary is on the low
side.

You  now  have  to execute a system call to indicate that the alternate stack
should be used.  Ths system call is sigaltstack() and it takes  2  arguments.
The  second  one  is how it returns the current state, and NULL is fine.  The
first is a pointer to a `stack_t', which is a  typedef'd  struct  having  the
following members:

    ss_sp           base address of signal stack
    ss_size         size of signal stack
    ss_flags        0

Next,  in  every  call to sigaction you should set the sa_flags member of the
struct sigaction to
    SA_RESTART | SA_ONSTACK
The SA_RESTART makes sure that any system call going on when  the  signal  is
delivered  will be restarted (instead of returning failure with errno EINTR).
The SA_ONSTACK is the flag that says to use the signal stack.

With this in place, there should be no  problem  with  interrupts.   When  an
interrupt  happens,  if  the  stack pointer does NOT point into the alternate
stack, it will be set to point there.  Then all the registers (including  the
original  stack  pointer)  will  be  saved on that stack and the process will
start running the signal handler code.

Note, if a signal comes in after sigaction has been called with SA_ONSTACK in
the  sa_flags  member  and  before sigaltstack() has been called, the process
will get a SIGSEGV, so the moral is call sigaltstack() first.