...
In this non-compliant code example, the program allocates a string on the heap, and uses it to log messages in a loop. The program also registers the signal handler int_handler()
to handle the terminal interrupt signal SIGINT
. The int_handler()
function sleeps for a short time, then logs the last message, calls free()
, and finally exits.
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> enum { MAXLINE = 1024 }; char *info = NULL; void log_message() { fprintf(stderr, info); } void handler(int signum) { sleep(1); log_message(); free(info); } int main(void) { signal(SIGINT, handler); info = (char*)malloc(MAXLINE); while (1) { /* main loop program code */ log_message(); /* more program code */ } return 0; } |
This program has four potential problems. The first is that the log_message()
function calls fprintf()
, which is an unsafe function to call from within a signal handler, because the handler might have been called when global data (such as stderr
) was in an inconsistent state. In general, standard I/O is never safe to invoke within a signal handler.
...
This example code achieves compliance with this rule by moving the final log message and call to free()
outside the signal handler. This signal handler still calls the sleep()
function, which is asynchronous-safe.
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> enum { MAXLINE = 1024 }; volatile sig_atomic_t eflag = 0; char *info = NULL; void log_message() { fprintf(stderr, info); } void handler(int signum) { eflag = 1; sleep(1); } int main(void) { signal(SIGINT, handler); info = (char*)malloc(MAXLINE); while (!eflag) { /* main loop program code */ log_message(); /* more program code */ } log_message(); free(info); return 0; } |
...