Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 发生堆栈溢出信号后如何清除堆栈_C_Multithreading_Posix_Pthreads - Fatal编程技术网

C 发生堆栈溢出信号后如何清除堆栈

C 发生堆栈溢出信号后如何清除堆栈,c,multithreading,posix,pthreads,C,Multithreading,Posix,Pthreads,在pthread中,到达堆栈中的黄色区域后,信号处理程序通过使递归函数返回来停止递归函数 但是,我们只能继续在黄色区域使用额外的区域 如何清理线堆黄色区域前的垃圾 (摘自“答案”): #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #定义ALT_堆栈大小(64*1024) #定义黄色区域页面(1) 类型定义结构{ 大小\u t堆栈\u大小; char*stack_指针; 字符*红色区域边界; 字符*黄色区域\边界; sigjmp_buf返回点; 大小\u t红色\u区域

在pthread中,到达堆栈中的黄色区域后,信号处理程序通过使递归函数返回来停止递归函数

但是,我们只能继续在黄色区域使用额外的区域

如何清理线堆黄色区域前的垃圾


(摘自“答案”):

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义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;