Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updated references from C11->C23

According to the C Standard Annex J.2 (133) [ISO/IEC 9899:2024], the behavior of a program is undefined when

the

...

value of errno is referred to after a signal occurred other than as the result of calling the abort

...

or raise

...

function and the corresponding signal handler obtained a SIG_ERR return from a call to the

...

Non-Compliant Code Example

signal function.

See undefined behavior 133.

A signal handler is allowed to call signal(); if that fails, signal() returns SIG_ERR and sets errno to a positive value. However, if the event that caused a signal was external (not the result of the program calling abort() or raise()), the only functions the signal handler may call are _Exit() or abort(), or it may call signal() on the signal currently being handled; if signal() fails, the value of errno is indeterminate.

This rule is also a special case of SIG31-C. Do not access shared objects in signal handlers. The object designated by errno is of static storage duration and is not a volatile sig_atomic_t. As a result, performing any action that would require errno to be set would normally cause undefined behavior. The C Standard, 7.14.1.1, paragraph 5, makes a special exception for errno in this case, allowing errno to take on an indeterminate value but specifying that there is no other undefined behavior. This special exception makes it possible to call signal() from within a signal handler without risking undefined behavior, but the handler, and any code executed after the handler returns, must not depend on the value of errno being meaningful.

Noncompliant Code Example

The handler() function in this noncompliant code example attempts to restore default handling for the signal indicated by signum. If the request to set the signal to default If the request to register a signal handler can be honored, the signal() function returns the value of the signal handler for the most recent successful call to the signal() function for the specified signal. Otherwise, a value of
SIG_ERR is returned and a positive value is stored in errno. Unfortunately, the value of errno is indeterminate because the handler() function is called when an external signal is raised, so any attempt to read errno (for example, by the perror() function) is undefined behavior:

Code Block
bgColor#FFcccc
langc

#include <signal.h>
#include <stdlib.h>
#include <string<stdio.h>

chartypedef void *err_msg;
volatile sig_atomic_t e_flag = 0(*pfv)(int);

void handler(int signum) {
  pfv old_handler = signal(signum, handlerSIG_DFL);
  e_flagif (old_handler = 1;
= SIG_ERR) {
    perror("SIGINT handler"); /* Undefined behavior */
    /* Handle error */
  }
}

int main(void) {
  pfv old_handler = signal(SIGINT, handler);

  if err(old_msghandler == (char *)malloc(24);
  if (err_msg == NULL) {
  SIG_ERR) {
    perror("SIGINT handler");
    /* Handle error */
  }

  /* handleMain errorcode conditionloop */

  return EXIT_SUCCESS;
}

The call to perror() from handler() also violates SIG30-C. Call only asynchronous-safe functions within signal handlers.

Compliant Solution

This compliant solution does not reference errno and does not return from the signal handler if the signal() call fails:

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include <stdlib.h>
#include  strcpy(err_msg, "No errors yet.");

  /* main code loop */<stdio.h>

typedef void (*pfv)(int);

void handler(int signum) {
  pfv old_handler = signal(signum, SIG_DFL);
  if (old_handler == SIG_ERR) {
    abort();
  }
}

int main(void) {
  pfv old_handler = signal(SIGINT, handler);
  if (e_flagold_handler == SIG_ERR) {
    strcpyperror(err_msg, "SIGINT received.handler");
    /* Handle error */
  }

  /* Main code loop */

  return 0EXIT_SUCCESS;
}

Compliant Solution

To be safe, signal handlers should only unconditionally set a flag of type volatile sig_atomic_t and return.

Noncompliant Code Example (POSIX)

POSIX is less restrictive than C about what applications can do in signal handlers. It has a long list of asynchronous-safe functions that can be called. (See SIG30-C. Call only asynchronous-safe functions within signal handlers.) Many of these functions set errno on error, which can lead to a signal handler being executed between a call to a failed function and the subsequent inspection of errno. Consequently, the value inspected is not the one set by that function but the one set by a function call in the signal handler. POSIX applications can avoid this problem by ensuring that signal handlers containing code that might alter errno; always save the value of errno on entry and restore it before returning.

The signal handler in this noncompliant code example alters the value of errno. As a result, it can cause incorrect error handling if executed between a failed function call and the subsequent inspection of errno:

Code Block
bgColor#FFcccc
langc
Code Block
bgColor#ccccff

#include <signal.h>
#include <stdlib.h>
#include <string<errno.h>
#include <sys/wait.h>

typedef void reaper(*pfv)(int);

char *err_msg;

void handler(int signum) {
  pfv old_handler = signal(signum, handler)int signum) {
  errno = 0;
  for (;;) {
    int rc = waitpid(-1, NULL, WNOHANG);
    if ((0 == rc) || (-1 == rc && EINTR != errno)) {
      break;
    }
  }
  if (ECHILD != errno) {
    /* Handle error */
  }
}

int main(void) {
  struct sigaction act;
  act.sa_handler = reaper;
  act.sa_flags = 0;
  if (old_handler == SIG_ERRsigemptyset(&act.sa_mask) != 0) {
	  perror("SIGINT handler"); /* undefinedHandle behaviorerror */
	
  }
  if (sigaction(SIGCHLD, &act, NULL) != 0) {
    /* handleHandle error condition*/
  }

  /* ... */

  return EXIT_SUCCESS;
}

Compliant Solution (POSIX)

This compliant solution saves and restores the value of errno in the signal handler:

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include  strcpy(err_msg, "SIGINT encountered.");
}

int main(void<stdlib.h>
#include <errno.h>
#include <sys/wait.h>

void reaper(int signum) {
  errno_t save_errno = errno;
  errno = 0;
  for (;;) {
   pfv old_handler int rc = signal(SIGINTwaitpid(-1, NULL, handlerWNOHANG);
    if ((0 == rc) || (old_handler-1 == SIG_ERRrc && EINTR != errno)) {
	  perror("SIGINT handler");
	      break;
    }
  }
  if (ECHILD != errno) {
    /* handleHandle error condition */
  }
  errno = save_errno;
}

int main(void) {
  struct sigaction act;
  erract.sa_msghandler = (char *)malloc(24) reaper;
  act.sa_flags = 0;
  if (err_msg == NULLsigemptyset(&act.sa_mask) != 0) {
    /* handleHandle error condition */
  }
  strcpy(err_msg, "No errors yet.");

if (sigaction(SIGCHLD, &act, NULL) != 0) {
    /* main code loop Handle error */
  }

  /* ... */

  return 0EXIT_SUCCESS;
}

Risk Assessment

Referencing indeterminate values of errno is undefined behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR32-C

1 (low)

1 (unlikely)

3 (low)

P3

L3

Low

Unlikely

Low

P3

L3

Automated Detection

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V

chained-errno-function-calls

errno-test-after-wrong-call

Supported
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-ERR32
Compass/ROSE



Could detect violations of this rule by looking for signal handlers that themselves call signal(). A violation is reported if the call fails and the handler therefore checks errno. A violation also exists if the signal handler modifies errno without first copying its value elsewhere

Coverity
Include Page
Coverity_V
Coverity_V

MISRA C 2012 Rule 22.8

MISRA C 2012 Rule 22.9

MISRA C 2012 Rule 22.10

Implemented
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-err32-cPartially implemented
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C2031

DF4781, DF4782, DF4783


Klocwork
Include Page
Klocwork_V
Klocwork_V

MISRA.INCL.SIGNAL.2012
MISRA.STDLIB.SIGNAL


LDRA tool suite
Include Page
LDRA_V
LDRA_V
44 SEnhanced enforcement
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V
CERT_C-ERR32-a

Properly use errno value

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule ERR32-CChecks for misuse of errno in a signal handler (rule fully covered)
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
chained-errno-function-calls
errno-test-after-wrong-call
Supported

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

...

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT C Secure Coding StandardSIG30-C. Call only asynchronous-safe functions within signal handlersPrior to 2018-01-12: CERT: Unspecified Relationship
CERT C Secure Coding StandardSIG31-C. Do not access shared objects in signal handlersPrior to 2018-01-12: CERT: Unspecified Relationship

Bibliography

...

9899:2024]Subclause 7.14.1.1,

...

"The

...

signal Function"


...

Image Added Image Added Image Added function"ERR31-C. Don't redefine errno      13. Error Handling (ERR)       ERR33-C. Only examine the value of errno when it is indicated to be valid by a function's return value