How to catch segmentation error on Linux?

I need to catch a segmentation error in third-party library cleanup operations. This happens sometimes before my program, and I cannot fix the real reason for this. In Windows programming, I could do this with __try - __catch. Is there a cross-platform or platform way to do the same? I need this on Linux, gcc.

+48
c ++ segmentation-fault try-catch
Feb 28 '10 at 8:11
source share
4 answers

On Linux, we may also have exceptions.

Usually, when your program executes a segmentation error, it sends a SIGSEGV signal. You can configure your own handler for this signal and mitigate the effects. Of course, you really have to be sure that you can recover from the situation. In your case, I think you should debug your code.

Return to the topic. I recently came across a library ( short guide ) that transforms such signals to exceptions, so you can write code as follows:

 try { *(int*) 0 = 0; } catch (std::exception& e) { std::cerr << "Exception catched : " << e.what() << std::endl; } 

Not tested, however. Works on my Gentoo x86-64 block. It has a backend for the platform (borrowed from the gcc java implementation), so it can work on many platforms. It just supports x86 and x86-64 out of the box, but you can get backends from libjava, which is in gcc sources.

+50
Feb 28 '10 at 8:37
source share

Here is an example of how to do this in 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; } 
+25
Mar 12 '10 at 22:40
source share

C ++ solution found here ( http://www.cplusplus.com/forum/unices/16430/ )

 #include <signal.h> #include <stdio.h> #include <unistd.h> void ouch(int sig) { printf("OUCH! - I got signal %d\n", sig); } int main() { struct sigaction act; act.sa_handler = ouch; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); while(1) { printf("Hello World!\n"); sleep(1); } } 
+6
Dec 23
source share

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

One option is to check it with isValidPtr() (works 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 are a bit more complicated (works on Android):

re_mprot.c:

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

re_mprot.h:

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

PS DLOG() - printf() for the Android magazine. FIRST_UNUSED_BIT() is defined here .

PPS It is not possible to call alloca () in a loop - memory can be freed until the function returns.

+2
Jun 06 '14 at 12:09 on
source share



All Articles