...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <signal.h>
#include <stdlib.h>
#include <string.h>
volatile char *err_msg;
void handler(int signum) {
strcpy(err_msg, "SIGINT encountered.");
}
int main(void) {
enum { MAX_MSG_SIZE = 24 };
signal(SIGINT, handler);
err_msg = (volatile char *)malloc(MAX_MSG_SIZE);
if (err_msg == NULL) {
/* Handle error condition. */
}
strcpy(err_msg, "No errors yet.");
/* Main code loop */
return 0;
}
|
...
Compliant Solution (Writing volatile sig_atomic_t)
In this noncompliant code example, Portably, signal handlers can only unconditionally set a variable of type volatile sig_atomic_t is read from and then written into before returning from the signal handler. Strictly conforming code cannot read from a volatile sig_atomic_t, only write into it. and return:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <signal.h> #include <stdlib.h> #include <string.h> volatile sig_atomic_t e_flag = 0; void handler(int signum) { if (0 == e_flag) { e_flag = 1; } } int main(void) { enum { MAX_MSG_SIZE = 24 }; char *err_msg = (char *)malloc(MAX_MSG_SIZE); if (err_msg == NULL) { /* Handle error condition */ } signal(SIGINT, handler); strcpy(err_msg, "No errors yet."); /* Main code loop */ if (e_flag) { strcpy(err_msg, "SIGINT received."); } return 0; } |
Compliant Solution (
...
Lock-free Atomic Access)
Signal handlers can refer to objects with static or thread storage duration that are lock-free atomic objects.Portably, signal handlers can only unconditionally set a variable of type volatile sig_atomic_t and return:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <signal.h> #include <stdlib.h> #include <string.h> volatile sig_#include <stdatomic.h> atomic_tint e_flag = ATOMIC_VAR_INIT(0); void handler(int signum) { int old_flag = atomic_load(&e_flag); if (old_flag != 0) { int new_flag; do { new_flag = 1; } while (!atomic_compare_exchange_weak(&e_flag, &old_flag, new_flag)); } } int main(void) { enum { MAX_MSG_SIZE = 24 }; char *err_msg = (char *)malloc(MAX_MSG_SIZE); if (err_msg == NULL) { /* Handle error condition */ } signal(SIGINT, handler); strcpy(err_msg, "No errors yet."); /* Main code loop */ if (e_flag) { strcpy(err_msg, "SIGINT received."); } return 0; } |
Compliant Solution (Lock-free Atomic Access)
Exceptions
SIG31-EX1: Due to the consensus formed at the April 2008 meeting of ISO/IEC WG14, it is acceptable to read a variable of type volatile sig_atomic_t as well as write it. In the following code example, a variable of type volatile sig_atomic_t is read and then written before returning from the signal handlerSignal handlers can refer to objects with static or thread storage duration that are lock-free atomic objects.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <signal.h> #include <stdlib.h> #include <string.h> #include <stdatomic.h> volatile sig_atomic_intt e_flag = ATOMIC_VAR_INIT(0); void handler(int signum) { int old_flag = atomic_load(&if (0 == e_flag); if (old_flag != 0) { int newe_flag; do { new_flag = 1; } while (!atomic_compare_exchange_weak(&e_flag, &old_flag, new_flag)); } } int main(void) { enum { MAX_MSG_SIZE = 24 }; char *err_msg = (char *)malloc(MAX_MSG_SIZE); if (err_msg == NULL) { /* Handle error condition */ } signal(SIGINT, handler); strcpy(err_msg, "No errors yet."); /* Main code loop */ if (e_flag) { strcpy(err_msg, "SIGINT received."); } return 0; } |
Exceptions
...
Risk Assessment
Accessing or modifying shared objects in signal handlers can result in accessing data in an inconsistent state. Michal Zalewski's paper "Delivering Signals for Fun and Profit" [Zalewski 2001] provides some examples of vulnerabilities that can result from violating this and other signal-handling rules.
...