Thread: blocking SIGSEGV

  1. #1
    Registered User
    Join Date
    Aug 2007
    Posts
    17

    blocking SIGSEGV

    i'm trying to block SIGSEGV, but don't know why the signal is not blocked.
    This is my code :

    Code:
    #include <iostream>
    #include <signal.h>
    #include <errno.h>
    
    using namespace std;
    
    sigset_t mSignalSet;
    
    int BlockSignal() {
    
    	if (sigprocmask(SIG_BLOCK, &mSignalSet, NULL) == -1) {
    		cout << "failed:" << strerror(errno) << endl;
    	}
    
    	return 1;
    }
    
    int UnblockSignal() {
    	if (sigprocmask(SIG_UNBLOCK, &mSignalSet, NULL) == -1) {
    		cout << "failed:" << strerror(errno) << endl;
    	}
    
    	return 1;
    }
    
    int main(int argc, char** args){
    
    	if ((sigemptyset(&mSignalSet) == -1) || (sigaddset(&mSignalSet, SIGSEGV)
    			== -1)) {
    		cout << "failed:" << strerror(errno) << endl;
    		return 1;
    	}
    
    	cout << "Block signal" << endl;
    
    	BlockSignal();
    
    	char* a = NULL;
    	a[1] = 'a';
    
    	sleep(2);
    
    	cout << "Unblock signal" << endl;
    
    	UnblockSignal();
    	
    	while(1){
    		sleep(1);
    	}
    
    	return 1;
    }
    Thanks

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    And exactly what behaviour do you expect to see from this?

    It may well be that you are successfully blocking the signal, but that you immediately get another SEGFAULT, because the OS returns to the same point, and after a sufficient number of segfaults, it will eventually say "Oh, so it's blocked, but I don't see any progress - lets unblock it".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    Quote Originally Posted by matsp View Post
    And exactly what behaviour do you expect to see from this?

    It may well be that you are successfully blocking the signal, but that you immediately get another SEGFAULT, because the OS returns to the same point, and after a sufficient number of segfaults, it will eventually say "Oh, so it's blocked, but I don't see any progress - lets unblock it".

    --
    Mats
    i have a shared memory that used by many module.
    To make it safe, of course i use semaphore.
    Before calling the semaphore to do the operation, i would like to block the signal (like SIGSEGV) first.
    After do some process, then unblock the signal.
    So it looks like this:

    block signal()
    semop -1 operation
    do some process
    semop +1 operation
    unblock signal()

    if i dont block signal, it will be deadlock if the program is terminated when doing some process.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Would it then not be better to have a signal handler that can "fix" the semaphore and then exit?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    Quote Originally Posted by matsp View Post
    Would it then not be better to have a signal handler that can "fix" the semaphore and then exit?

    --
    Mats
    i think i cant do that. Because the process inside the semaphore cannot be partly done.
    That's why i think it's better using signal block.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by sleith View Post
    i think i cant do that. Because the process inside the semaphore cannot be partly done.
    That's why i think it's better using signal block.
    But sigfault isn't guaranteed to be able to continue, because the processor normally sets the "return address" from the segfault to the beginning of failing instruction - so you would be trying to do the same thing again and again, ultimately locking up the process.

    Why would you segfault in this part of the code anyways? Surely accessing your shared memory should be possible at all times? If you are accessing other memory, perhaps you should package up your operations in a safe way BEFORE you start the process of shared memory, so that you know that the WHOLE operation can be completed as a single set of operations that will not fail - or not do the operation at all.

    If it can't be partly done, then accessing memory that gives you a segfault isn't a very "safe" thing to do, is it? What result do you expect from such an operation?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    Quote Originally Posted by matsp View Post
    But sigfault isn't guaranteed to be able to continue, because the processor normally sets the "return address" from the segfault to the beginning of failing instruction - so you would be trying to do the same thing again and again, ultimately locking up the process.

    Why would you segfault in this part of the code anyways? Surely accessing your shared memory should be possible at all times? If you are accessing other memory, perhaps you should package up your operations in a safe way BEFORE you start the process of shared memory, so that you know that the WHOLE operation can be completed as a single set of operations that will not fail - or not do the operation at all.

    If it can't be partly done, then accessing memory that gives you a segfault isn't a very "safe" thing to do, is it? What result do you expect from such an operation?

    --
    Mats
    the unblocking signal is just to handling in case when other modules using this ipc module is doing SIGSEGV.
    So the point is the ipc module is SAFE that guaranteed no segv or another thing happened that bother the semaphore process. The problem is in the module that use ipc module.
    Of course the module that use ipc module is hoped not to produce SIGSEGV or something that terminate ipc module unsafely

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    So, let me get this right:
    you have (an)other thread(s) that may segfault, and thus cause the semaphore to be left in a unknown state, causing other processes to be unable to access the shared memory, but the shared memory processing itself should not segfault?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    IMO, if you've got segfaults, you've got much bigger problems than leaving a semaphore in a locked state.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    Quote Originally Posted by matsp View Post
    So, let me get this right:
    you have (an)other thread(s) that may segfault, and thus cause the semaphore to be left in a unknown state, causing other processes to be unable to access the shared memory, but the shared memory processing itself should not segfault?

    --
    Mats
    Yes that's the situation. Of course the program should not produce segfault, but as a programmer i would like to do how to handling such thing if it happens. Btw, what makes my blocking signal code doesn't run as expected? i've tried with SIGINT and it's fine, but SIGSEGV and SIGABRT is failed to block.

    thanks

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by sleith View Post
    Yes that's the situation. Of course the program should not produce segfault, but as a programmer i would like to do how to handling such thing if it happens. Btw, what makes my blocking signal code doesn't run as expected? i've tried with SIGINT and it's fine, but SIGSEGV and SIGABRT is failed to block.

    thanks
    That's probably because (despite documentation saying otherwise), SIGSEGV is not blockable - it makes sense, as I have explained before, since you CAN NOT continue from a SEGV, since that will just cause an infinite loop of SEGV returning to the faulting instruction that faults again, etc, etc.

    My suggestion would be that you build a signal handler that deals with the issues arising from the segfault (such as killing the faulting thread, releasing semaphore, reverting shared memory, or whatever it is that you need to do).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Right I'm assuming you are using Linux or something compatible with it...

    Here's the ACTUAL signal handling code from 2.6.27:
    Code:
     928 int
     929 force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
     930 {
     931        unsigned long int flags;
     932        int ret, blocked, ignored;
     933        struct k_sigaction *action;
     934
     935        spin_lock_irqsave(&t->sighand->siglock, flags);
     936        action = &t->sighand->action[sig-1];
     937        ignored = action->sa.sa_handler == SIG_IGN;
     938        blocked = sigismember(&t->blocked, sig);
     939        if (blocked || ignored) {
     940                action->sa.sa_handler = SIG_DFL;
     941                if (blocked) {
     942                        sigdelset(&t->blocked, sig);
     943                        recalc_sigpending_and_wake(t);
     944                }
     945        }
     946        if (action->sa.sa_handler == SIG_DFL)
     947                t->signal->flags &= ~SIGNAL_UNKILLABLE;
     948        ret = specific_send_sig_info(sig, info, t);
     949        spin_unlock_irqrestore(&t->sighand->siglock, flags);
     950
     951        return ret;
     952 }
    A blocked signal is automatically unblocked when you receive that signal, which is how the "infinite loop" is solved. So the block works, it's just that you receive the same signal again immediately, which is why you do not think that it's working.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    hm.. if SIGSEGV is unblockable, then i should do with your suggest.
    ok thanks for your advice mats

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by sleith View Post
    hm.. if SIGSEGV is unblockable, then i should do with your suggest.
    ok thanks for your advice mats
    It is, technically, NOT unblockable. However, the "block" is a "oneshot", so it will automatically unblock the signal when you receive the first one, and the way almost all processors work on these type of faults is to set the return address such that it retries the failing instruction, so whilst it it possible to block the signal on the first attempt, very soon after (like nanoseconds or microseconds later) it will retry the same instruction, so unless something has changed [unlikely if it's just a bad pointer], then it will signal and stop the application.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    Aug 2007
    Posts
    17
    Quote Originally Posted by matsp View Post
    It is, technically, NOT unblockable. However, the "block" is a "oneshot", so it will automatically unblock the signal when you receive the first one, and the way almost all processors work on these type of faults is to set the return address such that it retries the failing instruction, so whilst it it possible to block the signal on the first attempt, very soon after (like nanoseconds or microseconds later) it will retry the same instruction, so unless something has changed [unlikely if it's just a bad pointer], then it will signal and stop the application.

    --
    Mats
    I try to send the signal for three times from self or from another program, and the signal SIGSEGV is blockable. Is it different because the system is not really SIGSEGV?
    Maybe i should sigaction the SIGSEGV, and for the backup i'll call the block signal, so if the signal is sent by another process, the signal is blockable, but if it's raise because it's process is segv where the signal is unblockable, it will raise the sigaction.

    Here the code where i try to send signal to self for 3 times
    Code:
    #include <iostream>
    #include <signal.h>
    #include <errno.h>
    
    using namespace std;
    
    sigset_t mSignalSet;
    
    int BlockSignal() {
    
    	if (sigprocmask(SIG_BLOCK, &mSignalSet, NULL) == -1) {
    		cout << "failed:" << strerror(errno) << endl;
    	}
    
    	return 1;
    }
    
    int UnblockSignal() {
    	if (sigprocmask(SIG_UNBLOCK, &mSignalSet, NULL) == -1) {
    		cout << "failed:" << strerror(errno) << endl;
    	}
    
    	return 1;
    }
    
    int main(int argc, char** args){
    
    	if ((sigemptyset(&mSignalSet) == -1) || (sigaddset(&mSignalSet, SIGSEGV)
    			== -1)) {
    		cout << "failed:" << strerror(errno) << endl;
    		return 1;
    	}
    
    	cout << "Block signal" << endl;
    
    	BlockSignal();
    
    	kill(getpid(), SIGSEGV);
    	kill(getpid(), SIGSEGV);
    	kill(getpid(), SIGSEGV);
    
    	sleep(2);
    
    	cout << "Unblock signal" << endl;
    
    	UnblockSignal();
    	
    	while(1){
    		sleep(1);
    	}
    
    	return 1;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Get faulting address on SIGSEGV
    By kruemelmonster in forum Linux Programming
    Replies: 12
    Last Post: 04-21-2009, 10:29 PM
  2. how to intilise a non blocking socket?
    By lolguy in forum Networking/Device Communication
    Replies: 7
    Last Post: 03-20-2009, 12:18 AM
  3. How to initialize a non blocking socket using only winsock library
    By *DEAD* in forum Networking/Device Communication
    Replies: 4
    Last Post: 01-18-2008, 07:03 AM
  4. Non blocking listen() with winsock
    By manwhoonlyeats in forum C Programming
    Replies: 1
    Last Post: 12-08-2002, 07:00 PM
  5. non blocking recv
    By rohit in forum Linux Programming
    Replies: 4
    Last Post: 03-05-2002, 09:35 PM