Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: moved 'read sigatomict' into exception

...

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 (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
bgColor#ffcccc#ccccff
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 (

...

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
bgColor#ccccff
langc
#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
bgColor#ccccff#ffcccc
langc
#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.

...