我已经看到至少三种不同的方法来为 sigaltstack() 设置替代堆栈。我想知道哪种方法最好:
方法#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");
}
方法#2
(我们已经使用了一段时间,但是这里分配的内存显示在泄漏检测中(leaks
命令))
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");
}
方法#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);
}
谢谢,阿科斯 (Mac OS X 10.8.2)
最佳答案
方法#1 是最好的。之所以是因为位置。假设您使用 #2 并且您的代码流如下所示:
void *blah = malloc (...)
...
stack_t sigstk;
sigstk.ss_size = 0;
sigstk.ss_flags = 0;
sigstk.ss_sp = malloc (SIGSTKSZ);
现在,如果您用完信号处理程序中的堆栈空间会发生什么?您的堆栈将向下增长并干扰 blah
指向的内存。如果你在某处有一些浅递归,它很容易发生。 #3 有同样的问题。
相反,使用 mmap,因为它从远离数据堆的不同池分配,并且设置保护页面是个好主意:
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();
...
现在,如果发生堆栈溢出,您将得到一个 SIGSEGV
,这比随机内存覆盖更容易调试 10 亿倍。 :)
#2 被算作泄漏的原因可能是误报。您正在使用的泄漏工具可能会用自己的变体覆盖 malloc
库函数,这是更喜欢使用 mmap
而不是 malloc< 来完成此任务的另一个原因
。
关于c - 如何正确设置sigaltstack?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14755341/