Interrupt function in C

Program 1:

#include<stdio.h> #include<signal.h> void handler(int sig); void main() { printf("PID: %d\n",getpid()); signal(SIGABRT,handler); while(1){ printf("Hai\n"); sleep(1); abort(); } } void handler(int sig) { printf("Signal handled\n"); } 

Output 1:

 $ ./a.out PID: 32235 Hai Signal handled Aborted (core dumped) $ 

According to the standard, the interrupt function works like raise(SIGABRT) . Thus, the signal generated by the abort() function is SIGABRT. Therefore, for this, I created the above program.

This program processes the SIGABRT signal. After the signal handler is executed, it does not return to the main function from which it is called. Why does it not return to the main function after the exit of the handler?

Program 2:

 #include<stdio.h> #include<signal.h> void handler(int sig); void main() { printf("PID: %d\n",getpid()); signal(SIGABRT,handler); while(1){ printf("Hai\n"); sleep(1); } } void handler(int sig) { printf("Signal handled\n"); } 

Output 2:

 $ ./a.out PID: 32247 Hai Hai Hai Signal handled Hai Signal handled Hai Hai ^C $ 

Unlike program 1, program 2 executes as expected. In the above program, signals are passed to the process through the command line through the kill command, as shown below.

 $ kill -6 32247 $ kill -6 32247 

So, as soon as the signal has occurred, the handler function is executed, and then returns to the main function. But this does not happen in program 1. Why does it behave this way? Function abort and SIGABRT are different?

+5
source share
5 answers

See this documentation from man 3 abort :

This leads to abnormal termination of the process if the SIGABRT signal is not caught and the signal handler does not return (see longjmp(3) ).

And also this:

If the SIGABRT signal is ignored or caught by the handler that returns, the abort() function will still terminate the process. He does this by restoring the default location for SIGABRT and then raising the signal a second time.

Thus, the only way to prevent abort() from interrupting from interrupting your program is from longjmp() -ing from the signal handler.

+5
source

The abort function sends a SIGABRT signal to true, but it does not matter if you catch (or ignore) that signal, the abort function will still exit your process.

On the man page:

RETURN VALUE

The abort() function never returns.

+1
source

Libc implements abort() . In its implementation, abort() checks if the process is alive because abort() is executed after raise(SIGABRT) . If so, then he knows that the user has processed SIGABRT . According to the documentation, this does not matter, because the process will still be completed:

You can see the exact implementation in the GLIBC source code ( stdlib/abort.c ):

 /* Cause an abnormal program termination with core-dump. */ void abort (void) { struct sigaction act; sigset_t sigs; /* First acquire the lock. */ __libc_lock_lock_recursive (lock); /* Now it for sure we are alone. But recursive calls are possible. */ /* Unlock SIGABRT. */ if (stage == 0) { ++stage; if (__sigemptyset (&sigs) == 0 && __sigaddset (&sigs, SIGABRT) == 0) __sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL); } /* Flush all streams. We cannot close them now because the user might have registered a handler for SIGABRT. */ if (stage == 1) { ++stage; fflush (NULL); } /* Send signal which possibly calls a user handler. */ if (stage == 2) { /* This stage is special: we must allow repeated calls of `abort' when a user defined handler for SIGABRT is installed. This is risky since the `raise' implementation might also fail but I don't see another possibility. */ int save_stage = stage; stage = 0; __libc_lock_unlock_recursive (lock); raise (SIGABRT); __libc_lock_lock_recursive (lock); stage = save_stage + 1; } /* There was a handler installed. Now remove it. */ if (stage == 3) { ++stage; memset (&act, '\0', sizeof (struct sigaction)); act.sa_handler = SIG_DFL; __sigfillset (&act.sa_mask); act.sa_flags = 0; __sigaction (SIGABRT, &act, NULL); } /* Now close the streams which also flushes the output the user defined handler might has produced. */ if (stage == 4) { ++stage; __fcloseall (); } /* Try again. */ if (stage == 5) { ++stage; raise (SIGABRT); } /* Now try to abort using the system specific command. */ if (stage == 6) { ++stage; ABORT_INSTRUCTION; } /* If we can't signal ourselves and the abort instruction failed, exit. */ if (stage == 7) { ++stage; _exit (127); } /* If even this fails try to use the provided instruction to crash or otherwise make sure we never return. */ while (1) /* Try for ever and ever. */ ABORT_INSTRUCTION; } 
+1
source

According to the standard, he did not fully define what should happen if you process SIGABRT :

The interrupt function causes abnormal termination of the program if the SIGABRT signal is not caught and the signal handler does not return. Regardless of whether open streams with unwritten buffer data are open, cleared, open streams are closed or temporary files are deleted. implementation. An implementation-defined status form of failure returns to the host environment using the function call raise (SIGABRT).

However, he indicated that he should not :

The interrupt function does not return to the caller.

Thus, proper behavior should ensure that an โ€œabnormal terminationโ€ occurs. This is provided by the abort function, which does it in the very best way to end the program abnormally, it does it by trying to finish it in various ways, and if nothing looks like a trick, it enters an endless loop (and at least ensures that it not returning to the caller).

0
source

They do not match. The abort function calls raise(SIGABRT) twice. If you defined a handler for SIGABRT , it will first call your handler and call the default value after that.

0
source

Source: https://habr.com/ru/post/1235360/


All Articles