通常在程序挂掉的时候我们会catch 他们挂掉的signal,然后在signal中打印出当时的一个stack,来方便问题调查, 但是在stack overflow的情况发生时,会没有拿到stack。signal的stack也是建立在thread的调用栈上的,在overflow的情况下,stack没有足够的空间来执行signal处理函数,signal处理函数就会被忽略。
示例代码:
main 主程序
#include <signal.h> #include <pthread.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include "mybacktrace.h" void recursiondeath() { char buffer[1024]; recursiondeath(); memset(buffer, 0xeb, sizeof(buffer)); printf("%d", buffer[0]); } void* threadloop(void* args) { // using sginal stack char altstack[SIGSTKSZ]; addsignalstack(altstack, SIGSTKSZ); recursiondeath(); return NULL; } int main(int argc, char const *argv[]) { char altstack[SIGSTKSZ]; registersignal(); addsignalstack(altstack, SIGSTKSZ); pthread_t t; pthread_create(&t, NULL, threadloop, NULL); pthread_join(t, NULL); return 0; }
mybacktrace.h 头文件
#include <execinfo.h> #include <signal.h> #include <assert.h> void signalhandler(int sig) { printf("signal revived [%d]\n", sig); // get the back trace enum { MAX_STACK = 32, }; void *stack[MAX_STACK]; int size = backtrace(stack, MAX_STACK); if(size == 0) { printf("fail to get backtrace\n"); } char** strs = backtrace_symbols(stack, size); int i = 0; for (i = 0; i < size; ++i) { printf("%s\n", strs[i]); } free(strs); signal(sig, SIG_DFL); } void addsignalstack(char *stack, int size) { assert(stack!=NULL); // using sginal stack stack_t sigstack; sigstack.ss_sp = stack; sigstack.ss_size = SIGSTKSZ; sigstack.ss_flags = 0; if (sigaltstack(&sigstack, 0) < 0) { perror("sig stack setting failed"); } } void registersignal() { struct sigaction act; act.sa_handler = signalhandler; act.sa_flags = SA_ONSTACK|SA_RESTART; int ret = sigaction(SIGSEGV, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } ret = sigaction(SIGBUS, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } ret = sigaction(SIGILL, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } }
说明:
添加signal alt stack
void addsignalstack(char *stack, int size) { assert(stack!=NULL); // using sginal stack stack_t sigstack; sigstack.ss_sp = stack; sigstack.ss_size = SIGSTKSZ; sigstack.ss_flags = 0; if (sigaltstack(&sigstack, 0) < 0) { perror("sig stack setting failed"); } }
这边由外部传进来的数组作为signal 处理函数执行用的stack
注册signal函数:
```
void registersignal() { struct sigaction act; act.sa_handler = signalhandler; act.sa_flags = SA_ONSTACK|SA_RESTART; int ret = sigaction(SIGSEGV, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } ret = sigaction(SIGBUS, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } ret = sigaction(SIGILL, &act, NULL); if (ret < 0) { perror("sigaction failed\n"); } }
注册了signal
SIGSEGV
SIGBUS
SIGILL
另外sigaction flag添加了SA_ONSTACK,确保当signal发生的时候,
signal处理函数会将sig atl stack作为函数frame
主函数:
int main(int argc, char const *argv[]) { char altstack[SIGSTKSZ]; registersignal(); addsignalstack(altstack, SIGSTKSZ); pthread_t t; pthread_create(&t, NULL, threadloop, NULL); pthread_join(t, NULL); return 0; }
执行前添加下signal的altstak,这里使用栈上的数组来作为signal处理函数的函数栈,可以通过malloc或者mmap分配.
线程的主函数
void* threadloop(void* args) { // using sginal stack char altstack[SIGSTKSZ]; addsignalstack(altstack, SIGSTKSZ); recursiondeath(); return NULL; }
执行前再添加下sig alt stack
注意:sig alt stack时每个线程自己单独的属性,所以每个线程都需要添加自己的sig alt stack