如何正确设置sigaltstack?

Áko*_*kos 5 c macos signals

我已经看到至少三种不同的方法来设置sigaltstack()的替代堆栈。我想知道哪一种是最好的方法:

\n

方法#1

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

方法#2\n(我们已经使用这个有一段时间了,但是这里分配的内存显示在泄漏检测(leaks命令)中)

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

方法#3

\n
stack_t sigstk;\nstatic char ssp[SIGSTKSZ];\nsigstk.ss_size = SIGSTKSZ;\nsigstk.ss_flags = 0;\nsigstk.ss_sp = ssp;\nsigstk.ss_size = SIGSTKSZ;\nif (sigaltstack (&sigstk, 0) < 0) {\n    sigstk.ss_size = 0;\n    free (sigstk.ss_sp);\n    printf ("sigaltstack errno=%d\\n", errno);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

谢谢,\xc3\x81kos\n(Mac OS X 10.8.2)

\n

Bjö*_*ist 6

方法#1 是最好的。究其原因,还是因为位置的原因。假设您使用 #2 并且您的代码流程如下:

void *blah = malloc (...)
...
stack_t sigstk;
sigstk.ss_size = 0;
sigstk.ss_flags = 0;
sigstk.ss_sp = malloc (SIGSTKSZ);
Run Code Online (Sandbox Code Playgroud)

现在,如果您耗尽信号处理程序中的堆栈空间,会发生什么?您的堆栈将向下增长并干扰 指向的内存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();
...
Run Code Online (Sandbox Code Playgroud)

现在,如果发生堆栈溢出,您将得到一个信息SIGSEGV,这比随机内存覆盖更容易调试十亿倍。:)

被算作泄漏的原因 #2 可能是误报。您使用的泄漏工具可能会使用malloc其自己的变体覆盖库函数,这是更喜欢使用mmap此任务而不是malloc.


Mul*_*ike 1

我不太熟悉sigaltstack(),但我一直在查看手册页。您的 3 种方法的区别似乎在于如何为ss_sp结构成员分配空间: use mmap()、 use classicmalloc()或从堆栈中分配它。

如果我正确理解系统,那么你绝对不想采用方法#3:从堆栈分配。退出函数后,堆栈空间将立即被回收并重新利用(即更改),并且会破坏sigaltstack().

所以我推荐传统的malloc()mmap()如果您喜欢语法,您可以选择。根据我的理解,将NULL地址传递给mmap()相当于malloc()无论如何。

  • 据我的理解,在方法 #3 中,“静态”存储类说明符不允许变量超出范围。 (2认同)