Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fairly major edits

Accessing or modifying shared objects in signal handlers can result in race conditions that can leave data in an inconsistent state. The exception to this rule is the ability to read and write to lock-free atomic objects or write to variables of volatile sig_atomic_t. The need for the volatile keyword is described in DCL22-C. Use volatile for data that cannot be cached. It is important to note that the behavior of a program that accesses an object of any other type from a signal handler is , including reading from a volatile sig_atomic_t is undefined. (See undefined behavior 131 in Appendix J of the C Standard.)

...

The signal handler may also call a handful of functions, including abort(). (See SIG30-C. Call only asynchronous-safe functions within signal handlers for details of functions that can be safely called from within signal handlers.)

Noncompliant Code Example (Non-atomic Access)

In this noncompliant code example, err_msg is updated to indicate that the SIGINT signal was delivered. Undefined behavior occurs if a SIGINT is generated before the allocation completes.

Code Block
bgColor#FFcccc
langc
#include <signal.h>
#include <stdlib.h>
#include <string.h>

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 = (char *)malloc(MAX_MSG_SIZE);
  if (err_msg == NULL) {
    /* Handle error condition. */
  }
  strcpy(err_msg, "No errors yet.");

  /* Main code loop */

  return 0;
}

Noncompliant Code Example (volatile with the Wrong Type)

This noncompliant code example declares volatile an object with static storage duration that is accessed in the signal handler. However, because the type of the object is not sig_atomic_t, the behavior of the program is undefined.

Code Block
bgColor#ffcccc
langc
#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

Noncompliant Code Example (Reading volatile sig_atomic_t)

In this noncompliant code example, a variable Portably, signal handlers can only unconditionally get or set a flag of type volatile sig_atomic_t and return: 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.

Code Block
bgColor#ccccff#ffcccc
langc
#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 (Writing volatile sig_atomic_t)

Portably, signal handlers can only unconditionally set a variable of type volatile sig_atomic_t and return:

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include <stdlib.h>
#include <string.h>

volatile sig_atomic_t e_flag = 0;

void handler(int signum) {
  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;
}

Noncompliant Code Example (volatile with the Wrong Type)

Compliant Solution (Lock-free Atomic Access)

Signal handlers can refer to objects with static or thread storage duration that are lock-free atomic objectsThis noncompliant code example declares volatile an object with static storage duration that is accessed in the signal handler. However, because the type of the object is not sig_atomic_t, the behavior of the program is undefined. Note that the behavior of the program is undefined also because the handler for the SIGFPE signal returns. See undefined behavior 129 in Appendix J of the C Standard.

Code Block
bgColor#ffcccc#ccccff
langc
#include <signal.h>
#include <stdlib.h>
extern double compute_value();

static volatile double value;

void sigfpe_#include <string.h>
#include <stdatomic.h>
 
atomic_int e_flag = ATOMIC_VAR_INIT(0);
 
void handler(int signum) {
  int old_flag = atomic_load(&e_flag);
  if (0.0 =old_flag != value0) {
    value = 1.0 int new_flag;
    do {
      new_flag = 1;
    } while (!atomic_compare_exchange_weak(&e_flag, &old_flag, new_flag));
  }
}

int main(void) {
  signal(SIGFPE, sigfpe_handler);
  value = compute_value(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

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. This exception transforms the "Reading volatile sig_atomic_t" noncompliant code example into a compliant solution.

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.

...

[C99 Rationale 2003]Subclause 5.2.3, "Signals and Interrupts"

 

...