C++ 如何在Linux中捕获分段错误?

C++ 如何在Linux中捕获分段错误?,c++,segmentation-fault,try-catch,C++,Segmentation Fault,Try Catch,我需要捕获第三方库清理操作中的分段错误。这种情况有时会发生在我的程序退出之前,我无法确定其真正原因。在Windows编程中,我可以使用uuu try-uu catch来实现这一点。是否有跨平台或特定于平台的方法来实现这一点?我在Linux中需要这个,gcc。在Linux上,我们也可以将这些作为例外 通常,当程序执行分段故障时,会发送一个SIGSEGV信号。您可以为该信号设置自己的处理程序,并减轻后果。当然,你真的应该确信你能从这种情况中恢复过来。在您的情况下,我认为您应该调试代码 回到话题上来。

我需要捕获第三方库清理操作中的分段错误。这种情况有时会发生在我的程序退出之前,我无法确定其真正原因。在Windows编程中,我可以使用uuu try-uu catch来实现这一点。是否有跨平台或特定于平台的方法来实现这一点?我在Linux中需要这个,gcc。

在Linux上,我们也可以将这些作为例外

通常,当程序执行分段故障时,会发送一个
SIGSEGV
信号。您可以为该信号设置自己的处理程序,并减轻后果。当然,你真的应该确信你能从这种情况中恢复过来。在您的情况下,我认为您应该调试代码

回到话题上来。我最近遇到()将此类信号转换为异常,因此您可以编写如下代码:

try
{
    *(int*) 0 = 0;
}
catch (std::exception& e)
{
    std::cerr << "Exception caught : " << e.what() << std::endl;
}
试试看
{
*(int*)0=0;
}
捕获(标准::异常&e)
{

下面是一个如何在C中实现的示例

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void segfault_sigaction(int signal, siginfo_t *si, void *arg)
{
    printf("Caught segfault at address %p\n", si->si_addr);
    exit(0);
}

int main(void)
{
    int *foo = NULL;
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = segfault_sigaction;
    sa.sa_flags   = SA_SIGINFO;

    sigaction(SIGSEGV, &sa, NULL);

    /* Cause a seg fault */
    *foo = 1;

    return 0;
}
#包括
#包括
#包括
#包括
无效SEGFULT\u SIGATION(内部信号、siginfo\u t*si、无效*参数)
{
printf(“在地址%p\n,si->si_addr处捕获到SEGFULT);
出口(0);
}
内部主(空)
{
int*foo=NULL;
struct-sigaction-sa;
memset(&sa,0,sizeof(struct-sigaction));
sigemptyset(和sa.sa_面具);
sa.sa_sigaction=segfault_sigaction;
sa.sa_flags=sa_SIGINFO;
sigaction(SIGSEGV,&sa,NULL);
/*导致seg故障*/
*foo=1;
返回0;
}
在此处找到C++解决方案()

#包括
#包括
#包括
虚空哎哟(内部信号)
{
printf(“哎哟!-我得到信号%d\n”,信号);
}
int main()
{
结构动作法;
act.sa_handler=哎哟;
sigemptyset(和act.sa_面具);
act.sa_标志=0;
sigation(SIGINT和act,0);
而(1){
printf(“你好,世界!\n”);
睡眠(1);
}
}

有时我们想要捕捉一个
SIGSEGV
来确定指针是否有效,也就是说,它是否引用了一个有效的内存地址。(或者甚至检查某个任意值是否可能是指针。)

一个选项是使用
isValidPtr()
(在Android上工作)进行检查:

int-isValidPtr(const-void*p,int-len){
如果(!p){
返回0;
}
int-ret=1;
int nullfd=open(“/dev/random”,仅限O_wr);
if(写入(nullfd,p,len)<0){
ret=0;
/*不好*/
}
关闭(nullfd);
返回ret;
}
int-isValidOrNullPtr(常量无效*p,int-len){
return!p | | isValidPtr(p,len);
}
另一个选项是读取内存保护属性,这有点棘手(在Android上工作):

re_mprot.c:

#包括
#包括
//#定义页面大小4096
#包括“dlog.h”
#包括“stdlib.h”
#包括“re_mprot.h”
结构缓冲区{
int pos;
整数大小;
char*mem;
};
字符*buf\U重置(结构缓冲区*b){
b->mem[b->pos]=0;
b->pos=0;
返回b->mem;
}
结构缓冲区*\u新缓冲区(整数长度){
结构缓冲区*res=malloc(sizeof(结构缓冲区)+长度+4);
res->pos=0;
res->size=长度;
res->mem=(无效*)(res+1);
返回res;
}
int_buf_putchar(结构缓冲区*b,int c){
b->mem[b->pos++]=c;
返回b->pos>=b->size;
}
void显示映射(void)
{
DLOG(“--------------------------------------------------------------\n”);
INTA;
文件*f=fopen(“/proc/self/maps”,“r”);
结构缓冲区*b=新缓冲区(1024);
而((a=fgetc(f))>=0){
如果(_buf_putchar(b,a)| a=='\n'){
DLOG(“/proc/self/maps:%s”,_buf_reset(b));
}
}
如果(b->pos){
DLOG(“/proc/self/maps:%s”,_buf_reset(b));
}
免费(b);
fclose(f);
DLOG(“--------------------------------------------------------------\n”);
}
无符号整数读取保护(void*addr){
INTA;
无符号整数res=MPROT_0;
文件*f=fopen(“/proc/self/maps”,“r”);
结构缓冲区*b=新缓冲区(1024);
而((a=fgetc(f))>=0){
如果(_buf_putchar(b,a)| a=='\n'){
char*end0=(void*)0;
无符号长地址0=strtoul(b->mem,&end0,0x10);
char*end1=(void*)0;
无符号长地址1=strtoul(end0+1,&end1,0x10);
如果((void*)addr0
re_mprot.h:

#包括


PPS给alloca()打电话可能不是个好主意在循环中,内存不能释放直到函数返回。对于可移植性,

,可能需要从标准C++库中使用<代码> STD::信号< /代码>,但是对信号处理程序所能做的限制很大。不幸的是,不可能从C++程序中捕获SIGSEVV<强>。导致未定义的行为,因为规范规定:

  • 从处理程序中调用任何库函数都是未定义的行为,而不是标准库函数的非常狭窄的子集(
    abort
    exit
    ,一些原子函数,重新安装当前信号处理程序,
    memcpy
    memmove
    ,类型特征,
    std::move
    std::forward
    ,等等)
  • 如果处理程序使用
    throw
    表达式,则这是未定义的行为
  • 如果医管局
    int isValidPtr(const void*p, int len) {
        if (!p) {
        return 0;
        }
        int ret = 1;
        int nullfd = open("/dev/random", O_WRONLY);
        if (write(nullfd, p, len) < 0) {
        ret = 0;
        /* Not OK */
        }
        close(nullfd);
        return ret;
    }
    int isValidOrNullPtr(const void*p, int len) {
        return !p||isValidPtr(p, len);
    }
    
    #include <errno.h>
    #include <malloc.h>
    //#define PAGE_SIZE 4096
    #include "dlog.h"
    #include "stdlib.h"
    #include "re_mprot.h"
    
    struct buffer {
        int pos;
        int size;
        char* mem;
    };
    
    char* _buf_reset(struct buffer*b) {
        b->mem[b->pos] = 0;
        b->pos = 0;
        return b->mem;
    }
    
    struct buffer* _new_buffer(int length) {
        struct buffer* res = malloc(sizeof(struct buffer)+length+4);
        res->pos = 0;
        res->size = length;
        res->mem = (void*)(res+1);
        return res;
    }
    
    int _buf_putchar(struct buffer*b, int c) {
        b->mem[b->pos++] = c;
        return b->pos >= b->size;
    }
    
    void show_mappings(void)
    {
        DLOG("-----------------------------------------------\n");
        int a;
        FILE *f = fopen("/proc/self/maps", "r");
        struct buffer* b = _new_buffer(1024);
        while ((a = fgetc(f)) >= 0) {
        if (_buf_putchar(b,a) || a == '\n') {
            DLOG("/proc/self/maps: %s",_buf_reset(b));
        }
        }
        if (b->pos) {
        DLOG("/proc/self/maps: %s",_buf_reset(b));
        }
        free(b);
        fclose(f);
        DLOG("-----------------------------------------------\n");
    }
    
    unsigned int read_mprotection(void* addr) {
        int a;
        unsigned int res = MPROT_0;
        FILE *f = fopen("/proc/self/maps", "r");
        struct buffer* b = _new_buffer(1024);
        while ((a = fgetc(f)) >= 0) {
        if (_buf_putchar(b,a) || a == '\n') {
            char*end0 = (void*)0;
            unsigned long addr0 = strtoul(b->mem, &end0, 0x10);
            char*end1 = (void*)0;
            unsigned long addr1 = strtoul(end0+1, &end1, 0x10);
            if ((void*)addr0 < addr && addr < (void*)addr1) {
                res |= (end1+1)[0] == 'r' ? MPROT_R : 0;
                res |= (end1+1)[1] == 'w' ? MPROT_W : 0;
                res |= (end1+1)[2] == 'x' ? MPROT_X : 0;
                res |= (end1+1)[3] == 'p' ? MPROT_P
                     : (end1+1)[3] == 's' ? MPROT_S : 0;
                break;
            }
            _buf_reset(b);
        }
        }
        free(b);
        fclose(f);
        return res;
    }
    
    int has_mprotection(void* addr, unsigned int prot, unsigned int prot_mask) {
        unsigned prot1 = read_mprotection(addr);
        return (prot1 & prot_mask) == prot;
    }
    
    char* _mprot_tostring_(char*buf, unsigned int prot) {
        buf[0] = prot & MPROT_R ? 'r' : '-';
        buf[1] = prot & MPROT_W ? 'w' : '-';
        buf[2] = prot & MPROT_X ? 'x' : '-';
        buf[3] = prot & MPROT_S ? 's' : prot & MPROT_P ? 'p' :  '-';
        buf[4] = 0;
        return buf;
    }
    
    #include <alloca.h>
    #include "re_bits.h"
    #include <sys/mman.h>
    
    void show_mappings(void);
    
    enum {
        MPROT_0 = 0, // not found at all
        MPROT_R = PROT_READ,                                 // readable
        MPROT_W = PROT_WRITE,                                // writable
        MPROT_X = PROT_EXEC,                                 // executable
        MPROT_S = FIRST_UNUSED_BIT(MPROT_R|MPROT_W|MPROT_X), // shared
        MPROT_P = MPROT_S<<1,                                // private
    };
    
    // returns a non-zero value if the address is mapped (because either MPROT_P or MPROT_S will be set for valid addresses)
    unsigned int read_mprotection(void* addr);
    
    // check memory protection against the mask
    // returns true if all bits corresponding to non-zero bits in the mask
    // are the same in prot and read_mprotection(addr)
    int has_mprotection(void* addr, unsigned int prot, unsigned int prot_mask);
    
    // convert the protection mask into a string. Uses alloca(), no need to free() the memory!
    #define mprot_tostring(x) ( _mprot_tostring_( (char*)alloca(8) , (x) ) )
    char* _mprot_tostring_(char*buf, unsigned int prot);
    
    int foo(int* p) {
        int x = *p;
        if(!p)
            return x; // Either UB above or this branch is never taken
        else
            return 0;
    }
     
    int main() {
        int* p = nullptr;
        std::cout << foo(p);
    }