The signal() function behaves differently in 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.
Different actions must be taken depending on whether or not you desire signal handlers to be persistent.
By default, *nix systems leave the handler in place after a signal is generated.
This non-complaint code example fails to persist the signal handler on Windows platforms.
#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;
}
|
When compiled with gcc 3.4.4 and executed under Red Hat Linux, the signal handler is automatically reinstalled upon handler execution.
% ./SIG01-A ^C Escaped from first while() ^C Escaped from second while() % |
However, when compiled with Microsoft Visual Studio 2005 version 8.0 and executed under Windows the signal handler is not automatically reinstalled.
> SIG01-A.exe ^C Escaped from first while() ^C > |
The second interrupt executes the default action for SIGINT, which is to terminate program execution.
A C99-compliant solution to persist the handler on a Windows system is to rebind the signal to the handler in the first line of the handler itself.
void handler(int signum) {
signal(signum, handler);
/* rest of handling code */
}
|
By default, *nix systems leave the handler in place after a signal is generated.
This non-complaint code example fails to reset the signal handler to its default action.
#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;
}
|
The compliant solution explicitly resets the signal handler to its implementation-defined default behavior.
#include <stdio.h>
#include <signal.h>
volatile sig_atomic_t e_flag = 0;
void handler(int signum) {
signal(signum, SIG_DFL);
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;
}
|
Failure to re-establish a persistent signal handler on Windows platforms can lead to unexpected behavior.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
SIG01-A |
1 (high) |
1 (likely) |
3 (low) |
P3 |
L3 |
\[[ISO/IEC 9899-1999TR2|AA. C References#ISO/IEC 9899-1999]\] "The {{signal}} function" |