How to set up sigaltstack correctly?

I've seen at least three different approaches to setting up an alternate stack for sigaltstack. I'm wondering which one is the best fit:

Approach # 1

stack_t sigstk;
sigstk.ss_size = 0;
sigstk.ss_flags = 0;
sigstk.ss_sp = mmap (NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (sigstk.ss_sp != MAP_FAILED) {
    sigstk.ss_size = SIGSTKSZ;
    if (sigaltstack (&sigstk, 0) < 0) {
        sigstk.ss_size = 0;
        printf ("sigaltstack errno=%d\n", errno);
    }
} else {
    printf ("malloc (SIGSTKSZ) failed!\n");
}

      

Approach # 2 (We've been using this for a while, but the memory allocated here is discovered when a leak is detected ("leak" command))

stack_t sigstk;
sigstk.ss_size = 0;
sigstk.ss_flags = 0;
sigstk.ss_sp = malloc (SIGSTKSZ);
if (sigstk.ss_sp != NULL) {
    sigstk.ss_size = SIGSTKSZ;
    if (sigaltstack (&sigstk, 0) < 0) {
        sigstk.ss_size = 0;
        free (sigstk.ss_sp);
        printf ("sigaltstack errno=%d\n", errno);
    }
} else {
    printf ("malloc (SIGSTKSZ) failed!\n");
}

      

Approach # 3

stack_t sigstk;
static char ssp[SIGSTKSZ];
sigstk.ss_size = SIGSTKSZ;
sigstk.ss_flags = 0;
sigstk.ss_sp = ssp;
sigstk.ss_size = SIGSTKSZ;
if (sigaltstack (&sigstk, 0) < 0) {
    sigstk.ss_size = 0;
    free (sigstk.ss_sp);
    printf ("sigaltstack errno=%d\n", errno);
}

      

Thank you Ákos (Mac OS X 10.8.2)

+3


source to share


2 answers


Approach # 1 is the best. The reason is that this is the place. Let's say you are using # 2 and your code flow looks like this:

void *blah = malloc (...)
...
stack_t sigstk;
sigstk.ss_size = 0;
sigstk.ss_flags = 0;
sigstk.ss_sp = malloc (SIGSTKSZ);

      

Now, what happens if you run out of stack space in a signal handler? Your stack will grow downward and interfere with the memory it points to blah

. This can happen if you have shallow recursion somewhere. # 3 has the same problem.

Use mmap instead, because it allocates from a different pool, away from the heap of data, and it is recommended to set up guard pages:



char* mem = mmap (NULL, 
                  SIGSTKSZ + 2*getpagesize(), 
                  PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 
                  -1, 0);
mprotect(mem, getpagesize(), PROT_NONE);
mprotect(mem + getpagesize() + SIGSTKSZ, getpagesize(), PROT_NONE);
sigstk.ss_sp = mem + getpagesize();
...

      

Now you get SIGSEGV

if a stack overflow occurs, which is about a billion times easier to debug than random memory being overwritten. :)

Reason # 2 is considered a leak, most likely a false position. The leak tool you are using is likely to override the library function malloc

with its own variant, which is another reason to prefer using it mmap

for this task over malloc

.

+2


source


I am not very familiar with sigaltstack()

, but I have looked through the man page . The difference in your three approaches is how to allocate space for a struct member ss_sp

: use mmap()

, use traditional, malloc()

or allocate it from the stack.

If I understand the system correctly, then you are absolutely not following approach # 3: allocate from the stack. Upon exiting this function, the stack space will be immediately reclaimed and repurposed (i.e. changed) and will break functionality sigaltstack()

.



Therefore, I would recommend the traditional one malloc()

. You can go with mmap()

if you like the syntax. In my opinion, the transfer of addresses NULL

in mmap()

any case equivalent malloc()

.

+1


source







All Articles