C 发生堆栈溢出信号后如何清除堆栈
在pthread中,到达堆栈中的黄色区域后,信号处理程序通过使递归函数返回来停止递归函数 但是,我们只能继续在黄色区域使用额外的区域 如何清理线堆黄色区域前的垃圾C 发生堆栈溢出信号后如何清除堆栈,c,multithreading,posix,pthreads,C,Multithreading,Posix,Pthreads,在pthread中,到达堆栈中的黄色区域后,信号处理程序通过使递归函数返回来停止递归函数 但是,我们只能继续在黄色区域使用额外的区域 如何清理线堆黄色区域前的垃圾 (摘自“答案”): #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #定义ALT_堆栈大小(64*1024) #定义黄色区域页面(1) 类型定义结构{ 大小\u t堆栈\u大小; char*stack_指针; 字符*红色区域边界; 字符*黄色区域\边界; sigjmp_buf返回点; 大小\u t红色\u区域
(摘自“答案”):
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义ALT_堆栈大小(64*1024)
#定义黄色区域页面(1)
类型定义结构{
大小\u t堆栈\u大小;
char*stack_指针;
字符*红色区域边界;
字符*黄色区域\边界;
sigjmp_buf返回点;
大小\u t红色\u区域\u大小;
}线程信息;
静态pthread\u键\u t thread\u info\u键;
静态结构sigaction newAct、oldAct;
bool gofromyellow=假;
int call_times=0;
静态无效主_例程(){
//让它溢出
如果(gofromyellow==true)
{
printf(“从黄色区域返回,调用%d次\n”,调用\u次);
返回;
}
其他的
{
通话次数=通话次数+1;
主_例程();
gofromyellow=真;
}
}
//红色区域管理
静态void stackoverflow_例程(){
fprintf(stderr,“堆栈溢出错误。\n”);
fflush(stderr);
}
//黄区管理
静态无效黄色\u区域\u挂钩(){
fprintf(标准“超出黄色区域”。\n”);
fflush(stderr);
}
静态整数获取堆栈信息(void**stackaddr,size\t*stacksize){
int-ret=-1;
pthread_attr_t attr;
pthread_attr_init(&attr);
if(pthread_getattr_np(pthread_self(),&attr)==0){
ret=pthread\u attr\u getstack(&attr,stackaddr,stacksize);
}
pthread_attr_destroy(&attr);
返回ret;
}
静态int是堆栈中的(常量ThreadInfo*tinfo,char*指针){
返回(tinfo->stack\u pointer stack\u pointer+tinfo->stack\u size);
}
静态int在红色区域中(常量ThreadInfo*tinfo,char*指针){
if(tinfo->红色区域\边界){
返回(tinfo->堆栈指针红色区域边界);
}
}
静态int位于黄色区域(常量ThreadInfo*tinfo,char*指针){
if(tinfo->黄色\u区域\u边界){
返回(tinfo->红色\区域\边界黄色\区域\边界);
}
}
静态无效集\黄色\区域(ThreadInfo*tinfo){
int pagesize=sysconf(_SC_PAGE_SIZE);
断言(页面大小>0);
tinfo->黄色区域边界=tinfo->红色区域边界+页面大小*黄色区域页面;
保护(tinfo->红色区域边界,页面大小*黄色区域页面,无保护);
}
静态无效重置黄色区域(ThreadInfo*tinfo){
大小页面大小=tinfo->黄色区域边界-tinfo->红色区域边界;
如果(mmap(tinfo->red_zone_boundary,pagesize,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,0,0)==0){
perror(“mmap失败”),退出(1);
}
mprotect(tinfo->红色区域边界、页面大小、保护读取、保护写入);
tinfo->黄色区域\边界=0;
}
静态无效信号处理器(int sig、siginfo\U t*sig\U info、void*sig\U数据){
if(sig==SIGSEGV){
ThreadInfo*tinfo=(ThreadInfo*)pthread\u getspecific(thread\u info\u key);
字符*故障地址=(字符*)信号信息->si地址;
if(在堆栈中(tinfo,故障地址)){
if(是否在红色区域(tinfo,故障地址)){
siglongjmp(tinfo->返回点,1);
}否则如果(是否在黄色区域(tinfo,故障地址)){
重置黄色区域(tinfo);
黄色_区_钩();
gofromyellow=真;
返回;
}否则{
//堆栈内部不相关溢出SEGV发生
}
}
}
}
静态无效寄存器\应用程序\信息(){
pthread\u key\u create(&thread\u info\u key,NULL);
sigemptyset(和newAct.sa_面具);
sigaddset(&newAct.sa_mask,SIGSEGV);
newAct.sa_sigaction=信号处理器;
newAct.sau flags=sau SIGINFO | sau RESTART | sau ONSTACK;
sigaction(SIGSEGV、newAct和oldAct);
}
静态无效寄存器线程信息(线程信息*tinfo){
堆叠;
pthread_setspecific(线程信息键,tinfo);
获取堆栈信息((void**)&tinfo->stack\u指针,&tinfo->stack\u大小);
printf(“堆栈大小%d mb\n”,tinfo->stack\u size/1024/1024);
tinfo->red\u zone\u boundary=tinfo->stack\u pointer+tinfo->red\u zone\u size;
设置黄色区域(tinfo);
ss.ss_sp=(char*)malloc(ALT_STACK_SIZE);
ss.ss_size=ALT_STACK_size;
ss.ss_标志=0;
sigaltstack(&ss,NULL);
}
静态void*thread_例程(void*p){
ThreadInfo*tinfo=(ThreadInfo*)p;
注册线程信息(tinfo);
如果(sigsetjmp(tinfo->返回点,1)==0){
主_例程();
}否则{
stackoverflow_例程();
}
免费(tinfo);
printf(“tinfo之后,结束线程\n”);
返回0;
}
int main(int argc,字符**argv){
注册应用程序信息();
如果(argc==2){
int stacksize=atoi(argv[1]);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,1024*1024*stacksize);
{
pthread_t pid0;
ThreadInfo*tinfo=(ThreadInfo*)calloc(1,sizeof(ThreadInfo));
pthread\u attr\u getguardsize(&attr,&tinfo->红色区域大小);
pthread_create(&pid0,&attr,thread_例程,tinfo);
pthread_join(pid0,NULL);
}
}否则{
printf(“用法:%s堆栈大小(mb)\n”,argv[0]);
}
返回0;
}
在linux的C语言中,ubuntu的信号处理程序是处理程序错误的糟糕方法。它们本质上是异步的,你能做的很少 递归函数也是一个坏主意——不能保证不会溢出堆栈。是的,您分配堆栈大小,是的,您正在处理溢出警告,但是必须有更好的方法来完成您想要做的事情。。。只需要一位同事在递归函数中添加一些堆栈局部变量,您就可以更改可能的递归数 无论如何,要回答你原来的问题
- 在年代
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> #include <sys/mman.h> #include <unistd.h> #include <assert.h> #include <sys/resource.h> #define ALT_STACK_SIZE (64*1024) #define YELLOW_ZONE_PAGES (1) typedef struct { size_t stack_size; char* stack_pointer; char* red_zone_boundary; char* yellow_zone_boundary; sigjmp_buf return_point; size_t red_zone_size; } ThreadInfo; static pthread_key_t thread_info_key; static struct sigaction newAct, oldAct; bool gofromyellow = false; int call_times = 0; static void main_routine(){ // make it overflow if(gofromyellow == true) { printf("return from yellow zone, called %d times\n", call_times); return; } else { call_times = call_times + 1; main_routine(); gofromyellow = true; } } // red zone management static void stackoverflow_routine(){ fprintf(stderr, "stack overflow error.\n"); fflush(stderr); } // yellow zone management static void yellow_zone_hook(){ fprintf(stderr, "exceed yellow zone.\n"); fflush(stderr); } static int get_stack_info(void** stackaddr, size_t* stacksize){ int ret = -1; pthread_attr_t attr; pthread_attr_init(&attr); if(pthread_getattr_np(pthread_self(), &attr) == 0){ ret = pthread_attr_getstack(&attr, stackaddr, stacksize); } pthread_attr_destroy(&attr); return ret; } static int is_in_stack(const ThreadInfo* tinfo, char* pointer){ return (tinfo->stack_pointer <= pointer) && (pointer < tinfo->stack_pointer + tinfo->stack_size); } static int is_in_red_zone(const ThreadInfo* tinfo, char* pointer){ if(tinfo->red_zone_boundary){ return (tinfo->stack_pointer <= pointer) && (pointer < tinfo->red_zone_boundary); } } static int is_in_yellow_zone(const ThreadInfo* tinfo, char* pointer){ if(tinfo->yellow_zone_boundary){ return (tinfo->red_zone_boundary <= pointer) && (pointer < tinfo->yellow_zone_boundary); } } static void set_yellow_zone(ThreadInfo* tinfo){ int pagesize = sysconf(_SC_PAGE_SIZE); assert(pagesize > 0); tinfo->yellow_zone_boundary = tinfo->red_zone_boundary + pagesize * YELLOW_ZONE_PAGES; mprotect(tinfo->red_zone_boundary, pagesize * YELLOW_ZONE_PAGES, PROT_NONE); } static void reset_yellow_zone(ThreadInfo* tinfo){ size_t pagesize = tinfo->yellow_zone_boundary - tinfo->red_zone_boundary; if(mmap(tinfo->red_zone_boundary, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0) == 0){ perror("mmap failed"), exit(1); } mprotect(tinfo->red_zone_boundary, pagesize, PROT_READ | PROT_WRITE); tinfo->yellow_zone_boundary = 0; } static void signal_handler(int sig, siginfo_t* sig_info, void* sig_data){ if(sig == SIGSEGV){ ThreadInfo* tinfo = (ThreadInfo*) pthread_getspecific(thread_info_key); char* fault_address = (char*) sig_info->si_addr; if(is_in_stack(tinfo, fault_address)){ if(is_in_red_zone(tinfo, fault_address)){ siglongjmp(tinfo->return_point, 1); }else if(is_in_yellow_zone(tinfo, fault_address)){ reset_yellow_zone(tinfo); yellow_zone_hook(); gofromyellow = true; return; } else { //inside stack not related overflow SEGV happen } } } } static void register_application_info(){ pthread_key_create(&thread_info_key, NULL); sigemptyset(&newAct.sa_mask); sigaddset(&newAct.sa_mask, SIGSEGV); newAct.sa_sigaction = signal_handler; newAct.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; sigaction(SIGSEGV, &newAct, &oldAct); } static void register_thread_info(ThreadInfo* tinfo){ stack_t ss; pthread_setspecific(thread_info_key, tinfo); get_stack_info((void**)&tinfo->stack_pointer, &tinfo->stack_size); printf("stack size %d mb\n", tinfo->stack_size/1024/1024 ); tinfo->red_zone_boundary = tinfo->stack_pointer + tinfo->red_zone_size; set_yellow_zone(tinfo); ss.ss_sp = (char*)malloc(ALT_STACK_SIZE); ss.ss_size = ALT_STACK_SIZE; ss.ss_flags = 0; sigaltstack(&ss, NULL); } static void* thread_routine(void* p){ ThreadInfo* tinfo = (ThreadInfo*)p; register_thread_info(tinfo); if(sigsetjmp(tinfo->return_point, 1) == 0){ main_routine(); } else { stackoverflow_routine(); } free(tinfo); printf("after tinfo, end thread\n"); return 0; } int main(int argc, char** argv){ register_application_info(); if( argc == 2 ){ int stacksize = atoi(argv[1]); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 1024 * 1024 * stacksize); { pthread_t pid0; ThreadInfo* tinfo = (ThreadInfo*)calloc(1, sizeof(ThreadInfo)); pthread_attr_getguardsize(&attr, &tinfo->red_zone_size); pthread_create(&pid0, &attr, thread_routine, tinfo); pthread_join(pid0, NULL); } } else { printf("Usage: %s stacksize(mb)\n", argv[0]); } return 0; }
return;