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