问题
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 thelongjmp
to unmask it yourself. - You can install the signal handler with
sigaction
(the preferred way to do it anyway) and use theSA_NODEFER
flag to prevent it from being masked. - You can use the
sigsetjmp
andsiglongjmp
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