I have seen at least three different approaches to set up the alternative stack for sigaltstack(). I'm wondering which one is the best approach:
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 shows up in leak detection (leaks
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);
}
Thanks, Ákos (Mac OS X 10.8.2)
Approach #1 is the best. The reason why is because of location. Suppose you use #2 and your code flow goes 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 exhaust your stack space in your signal handler? Your stack will grow downwards and interfere with the memory pointed to by blah
. It can easily happen if you have some shallow recursion somewhere. #3 has the same kind of problem.
Instead, use mmap because it allocates from a different pool, far away from the data heap, and it is a good idea to setup 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'll get a SIGSEGV
if a stack overflow occurs which is about a billion times easier to debug than random memory overwrites. :)
The reason #2 is counted as a leak is likely a false positive. The leaks tool you are using likely overrides the malloc
library function with its own variant, which is another reason to prefer to use mmap
for this task rather than malloc
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With