The signal()
function has implementation-defined behavior and behaves differently, for example, on Windows than it does on Linux/BSD systems. When a signal handler is installed with the signal()
function in Windows, the default action is restored for that signal after the signal is triggered. Conversely, Linux/BSD systems leave the signal handler defined by the user in place until it is explicitly removed.Unix systems.
The following example code illustrates this behavior:
Code Block |
---|
#include <stdio.h> #include <signal.h> volatile sig_atomic_t e_flag = 0; void handler(int signum) { e_flag = 1; } int main(void) { signal(SIGINT, handler); while (!e_flag) {} puts("Escaped from first while ()"); e_flag = 0; while (!e_flag) {} puts("Escaped from second while ()"); return 0; } |
*nix Unix (and Unix-like) systems automatically reinstall signal handlers upon handler execution, meaning that the signal handler defined by the user in place until it is explicitly removed. For example, when this code is compiled with gcc 3.4.4 and executed under Red Hat Linux, the SIGINT
is captured both times by handler
.
Code Block |
---|
% ./SIG01-A ^C Escaped from first while () ^C Escaped from second while () % |
However, under Windows systems When a signal handler is installed with the signal()
function in Windows, the default action is restored for that signal after the signal is triggered. This means that signal handlers are not automatically reinstalled. For example, when this code is compiled with Microsoft Visual Studio 2005 version 8.0, only the first SIGINT
is captured by handler
.
...
Different actions must be taken depending on whether or not you desire signal handlers to be persistent.
Persistent Handlers
By default, *nix systems leave the handler in place after a signal is generated, whereas Windows system do Errors and potential vulnerabilities exist when the actual signal handler persistence behavior is inconsistent with the developer's expectations, for example, the developer expects the signal handler to persist but it does not.
Non-Compliant Code Example (Windows)
...
Code Block | ||
---|---|---|
| ||
void handler(int signum) { #ifdef WINDOWS signal(signum, handler); #endif /* handling code */ } |
Non-Persistent Handlers
By default, Windows systems reset the signal handler to its default action after a signal is generated, whereas *nix system do notErrors may also occur when the developer expects the default action to be restored for a signal, but instead, the signal handler persists.
Non-Compliant Code Example (
...
Unix)
This non-complaint code example fails to reset the signal handler to its default behavior on *nix Unix systems.
Code Block | ||
---|---|---|
| ||
void handler(int signum) { /* handling code */ } |
Compliant Solution (
...
Unix)
A C99-compliant solution to reset the handler on a *nix Unix system is to rebind the signal to the implementation-defined default handler in the first line of the handler itself.
...