linux 捕获错误,如何在Linux中捕获分段错误?

Sometimes we want to catch a SIGSEGV to find out if a pointer is valid, that is, if it references a valid memory address. (Or even check if some arbitrary value may be a pointer.)

One option is to check it with isValidPtr() (worked on Android):

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);

}

Another option is to read the memory protection attributes, which is a bit more tricky (worked on Android):

re_mprot.c:

#include

#include

//#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;

}

re_mprot.h:

#include

#include "re_bits.h"

#include

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);

PS DLOG() is printf() to the Android log. FIRST_UNUSED_BIT() is defined here.

PPS It may not be a good idea to call alloca() in a loop -- the memory may be not freed until the function returns.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值