I've made the follow signal handler
struct sigaction pipeIn;
pipeIn.sa_handler = updateServer;
sigemptyset(&pipeIn.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGUSR1, &pipeIn, NULL) == -1){
printf("We have a problem, sigaction is not working.\n");
perror("\n");
exit(1);
}
How do I remove or block this particular handler so that I can set up another signal handler that uses the same signal? Thanks.
Use SIG_DFL in place of the function pointer when calling sigaction(2).
Related
jmp_buf functjmp;
void sigsegv_handler(int sig) {
sio_printf("Caught sigsegv!\n");
siglongjmp(functjmp, 2);
return;
}
void foo(unsigned val) {
assert(0);
sio_printf("entered!\n");
}
int main() {
struct sigaction action;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
sigaddset(&action.sa_mask, SIGSEGV);
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
sigset_t prev_mask;
sigprocmask(SIG_BLOCK, NULL, &prev_mask);
if (sigsetjmp(functjmp, 0) == 0) {
foo(*(unsigned *)0x8);
} {
sigprocmask(SIG_BLOCK, &prev_mask, NULL);
sio_printf("jump handled!\n");
foo(*(unsigned *)0x8);
}
sio_fprintf(stderr, "how did it come here?!\n");
}
I've been debugging this code using gdb, and I cannot figure out why the program will not handle the second SIGSEGV signal with my own handler, assuming no other signals were received or sent by the program? Any sio prefixed functions are async safe variants of the stdio counterparts.
Currently, I surmise it has to do with something I'm missing in my conception about returning from the signal handler, which longjmp doesn't do at all.
Short answer: normally not possible to resume after SIGSEGV for C program. You might get more mileage with C++.
Long Answer: See discussions in Coming back to life after Segmentation Violation
Assuming OK to take the risk of undefined behavior:
It is possible to re-enable SEGV. The core issue is that during signal handler, the code explicitly blocks the SEGV signal from being triggered (with the sigaddset). In addition, the default behavior (of signal handlers) is that during signal handling, the same signal processing will be deferred until the signal handler returns. In the OP code, the signal handler never returns (because of the siglongjmp)
Both issues can be addressed by changing the original code.
// Make sure all attributes are NULL.
struct sigaction action = {} ;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
// Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
// Add SA_NODEFER to disable the deferred processing of SIGSEGV.
action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */
// rest of code here
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
...
I'm trying to handle some of the C signals in the program I'm writing to add some safety nets in case of accidental closure etc. I've been trying to set up a signal handler for SIGINT using sigaction, and I can see the handler is being called, but it's not stopping the program from being killed anyway.
Trying to use signal with SIG_IGN works fine, however stops me being able to use custom handling. I've tried using signal(...) with my handler, and sigaction(...), and neither are actually working.
void handler(int SIG) {
//I know this is unsafe just for testing.
printf("Handled signal %d!\n", SIG);
//No actual logic for now.
}
void initializer() {
//...
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
//This doesn't work.
sigaction(SIGINT, &sa, NULL);
//This also didn't work.
// signal(SIGINT, handler);
//...
}
I believed that handling the signal would stop it by default, and everything I've seen online has indicated this should be enough, but I still receive:
^CHandled signal 2!
And then the process is killed...
I tried to find an answer to my question at this post: Signal handler and waitpid coexisting but for me isn't very clear at the moment.
I try to explain my problems:
I'm trying to write a C program that concerns IPC between a parent process and its children.
The parent process creates N child processes, then it waits for the termination in a loop like this:
while((pid_term = waitpid(-1, &status, 0)) != -1)
After X seconds, parent receives SIGALRM, then with the sigaction system call,
it catches the alarm:
struct sigaction act;
act.sa_handler = alarmHandler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
But, when the handler function returns, the waitpid also returns -1, and the parent process exits from the while loop above.
At the moment, the handler function has an empty body.
I ask myself what happened — why did waitpid() return -1 after the handler invocation even though most of the children are still alive? Why doesn't this happen with signal() function?
The default behavior of signal handlers established by sigaction is to interrupt blocking system calls; if you check errno after the alarm fires you should observe it to be set to EINTR. This behavior is almost never what you want; it's only the default for backward compatibility's sake. You can make it not do this by setting the SA_RESTART bit in sa_flags:
struct sigaction act;
act.sa_flags = SA_RESTART;
act.sa_handler = alarmHandler;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, 0);
One of the most important reasons to use sigaction instead of signal, is that when you use signal it is unpredictable whether or not the signal handler will interrupt blocking system calls. (The System V lineage picked one semantic and the BSD lineage picked the other.)
I have a program that needs to use one custom signal handler for SIGINT and one for SIGCHILD.
I therefore added two struct sigaction called sigchildStruct and sigintStruct, and used sigaction to define two custo signal handling functions: handleSigInt() and handleSigChild()
First of all, is this the way you are supposed to do it; needing to register two separate sigaction structs?
Second of all, i need to block SIGCHILD during part of the code execution, i only want to receive the signal at one place in the code, so i used:
sigdelset(&sigchildStruct.sa_mask,SIGCHLD);
// Catch SIGCHILD signal here
sigaddset(&sigchildStruct.sa_mask,SIGCHLD);
Is that how you would do that? More importantly: there are two sigaction structs, but do i only need to change the sa_mask on one of them, or on both? Now i only changed the sa_mask on the struct called sigchildStruct, and not on the one called sigintStruct.
The rest of the code:
void handleSigchild(int sig) {
int childPID,childExitStatus;
printf("\nSIGCHILD received\n");
while ((childPID = waitpid(-1,&childExitStatus,WNOHANG)) >0) {
if (childExitStatus==2) {printf("Background process: %d%s",childPID," terminated by SIGINT\n");}
else if (childExitStatus!=0) {printf("Background process: %d%s",childPID," unknown command\n");}
printf("Background process: %d%s\n",childPID," has exited");
}
}
void handleSigInt(int sig) {
// SIGINT will be sent to all child processes so nothing needs to be done
printf("\nSIGINT received\n");
}
int main(int argc, char ** argv) {
// Sigaction for SIGCHILD
struct sigaction sigchildStruct;
sigchildStruct.sa_handler = &handleSigchild;
sigemptyset(&sigchildStruct.sa_mask);
sigaddset(&sigchildStruct.sa_mask,SIGCHLD);
sigchildStruct.sa_flags = SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sigchildStruct, 0) == -1) {
printf("Couldnt register signal handler: %s\n",strerror(errno));
exit(1);
}
// Sigaction for SIGINT
struct sigaction sigintStruct;
sigintStruct.sa_handler = &handleSigInt;
sigemptyset(&sigintStruct.sa_mask);
sigintStruct.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sigintStruct, 0) == -1) {
printf("Couldnt register signal handler: %s\n",strerror(errno));
exit(1);
}
sigdelset(&sigchildStruct.sa_mask,SIGCHLD);
// Catch SIGCHILD signal here
sigaddset(&sigchildStruct.sa_mask,SIGCHLD);
}
Because nobody answered, I'll try to do so. When I am dealing with signals I am using the function signal. This function takes two parameters: signal code and signal handler function. To start catching the signals I would put the code:
signal(SIGINT, handleSigInt);
signal(SIGCHILD, handleSigChild);
To stop catching the signal, I would execute:
signal(SIGINT, SIG_IGN);
signal(SIGCHILD, SIG_IGN);
Hope it helps.
There is several mistakes in your code.
1) It is not necessary to add SIGCHLD signal in the set of blocked signals during its handling. Every catched signal is blocked during its handling, so that there is no concurrent reentrance in the handling function :
struct sigaction sigchildStruct;
sigchildStruct.sa_handler = &handleSigchild;
sigemptyset(&sigchildStruct.sa_mask);
// sigaddset(&sigchildStruct.sa_mask,SIGCHLD); // unnecessary
sigchildStruct.sa_flags = SA_NOCLDSTOP;
2) You modified the sa_mask value of the struct after setting the action, which has no effect. If you want to block the delivery of signals for some time you need to modify the process signal mask. There is a function to do that : sigprocmask. So you can do something like :
sigset_t oldMask, newMask;
sigemptyset(&newMask);
sigaddset(&newMask,SIGCHLD);
sigprocmask(SIG_BLOCK,&newMask,&oldMask);
// now protected from SIGCHLD delivery, signal will be blocked...
sigprocmask(SIG_SETMASK,&oldMask,NULL);
// old protection reinstalled...
I am trying to catch a SIGSEGV from my program. I got a problem that my signal_handler doesn't catch the signal.
void handler(int sig){
printf("catch SIGSEGV");
exit(EXIT_FAILURE);
}
void foo(){
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
if(sigaction(SIGSEGV, &sa, NULL) == -1){
handle_error("sigaction");
}
/* if SIGSEGV happen here, I can catch it */
bar();
}
void bar() {
/* if SIGSEGV happen here, I cannot catch it */
}
Is that means I have to install another signal handler inside bar?
But what if I have a bunch of function that want to catch the same signal. I have to install the signal handler for multiple times?
Update :
I tried to install the handler directly in the function but still cannot catch it. So I think it might be other problem. But that pretty weird. I use gdb to run and get
Program received signal SIGSEGV, Segmentation fault.
0x080499b1 in is_printable_string (
str=0xb80fe768 <Address 0xb80fe768 out of bounds>)
at trace/trace.c:259
259 while(str[index]!='\0'){
and this is my is_printable_String
int is_printable_string(char *str){
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
if(sigaction(SIGSEGV, &sa, NULL) == -1){
handle_error("sigaction");
}
int index;
index=0;
while(str[index]!='\0'){
if(!isprint(str[index])){
return -1;
}
index++;
}
/* continue... */
This seems like I got a SEG fault, but I can't catch it
I intentionally passed that pointer, so nothing wrong with str parameter.
from the man page of sigaction ...
SA_SIGINFO (since Linux 2.2) The signal handler takes three arguments,
not one. In this case, sa_sigaction should be set instead of
sa_handler. This flag is only meaningful when establishing a signal
handler.
Therefore, your issue should be the line
sa.sa_flags = SA_SIGINFO;
Change it to
sa.sa_flags = 0;
and see how it goes.
Indeed as ajcaruana points out your handler doesn't match SA_SIGINFO. But if you are catching SIGSEGV you likely want SA_SIGINFO, to look at the offending address and stuff. In that case your signal handler needs to look like this:
static void
handler(int sig, siginfo_t *si, void *ucontext)
{
/* ... */
}
In particular, you might be interested in si_addr:
For the SIGBUS and SIGSEGV signals, this field contains the address
that caused the invalid memory reference.