Catching Segmentation Violations and Getting on with Life

好久不见. 提交于 2019-12-20 03:22:00

问题


I'm writing a program that's examining its own address space.

Specifically, I care about all malloc-ed data blocks. If there some system call to get a list of them, that would be fantastic (for my application, I cannot use LD_PRELOAD, -wrap, nor any extra command line options). If there's a way to do this, I'd love to hear it even more than an answer to my stated problem, below.

In lieu of this, my current approach is to just dereference everything and look around. Obviously, the set of all possible pointers is a minefield of segfaults waiting to happen, so I tried registering a signal handler and using setjmp/longjmp (simply ignoring the segfault by making the handler do nothing is an infinite loop because the handler will return to the faulting instruction). Some example code goes like so:

static jmp_buf buf;
void handler(int i) {
    printf("    Segfaulted!\n");
    longjmp(buf,-1);
}
void segfault(void) {
    int* x = 0x0;
    int y = *x;
}
void test_function(void) {
    signal(11,handler);
    while (1) {
        if (setjmp(buf)==0) {
            printf("Segfaulting:\n");
            segfault();
        }
        else {
            printf("Recovered and not segfaulting!\n");
        }
        printf("\n");
    }
}

The output is:

    Segfaulting:
        Segfaulted!
    Recovered and not segfaulting!

    Segfaulting:
    Segmentation fault

So, the handler didn't work the second time around. I don't know why this is, but I speculated it had something to do with not clearing the original signal. I don't know how to do that.

As an aside, I tried sigsetjmp/siglongjmp first, but they weren't defined for some reason in setjmp.h. I got vague vibes that one needed to pass some extra compile flags, but, as before, that is not allowed for this application.

The system being used is Ubuntu Linux 10.04 x86-64, and any solution does not need to be portable.

Thanks!
Ian[

EDIT: sigrelse in the handler clears the signal, and fixes the problem effectively. Question now concerns the other issues raised--is there a better way (i.e., get the blocks of malloc)? What's up with sigsetjmp/siglongjmp? Why do I need to reset the signal?]


回答1:


When the signal handler for SIGSEGV is invoked, the SIGSEGV signal will be masked as if by sigprocmask. This is true for any signal. Normally returning from the signal handler would unmask it, but since you're not returning, that never happens. There are a couple possible solutions:

  • You can call sigprocmask either before or after the longjmp to unmask it yourself.
  • You can install the signal handler with sigaction (the preferred way to do it anyway) and use the SA_NODEFER flag to prevent it from being masked.
  • You can use the sigsetjmp and siglongjmp functions, which themselves take responsibility for saving and restoring the signal mask.



回答2:


signal() is a legacy interface, and may or may not re-register a signal handler after it has been invoked, depending on the OS; you may need to issue another signal() call to reset the signal handler as the last action in your handler. See man 2 signal.

sigaction() is the preferred mechanism to set signal handlers, as it has well defined and portable behavior.



来源:https://stackoverflow.com/questions/10307739/catching-segmentation-violations-and-getting-on-with-life

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!