Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

A signal handler should not re-assert reassert its desire to handle its own signal. This is often done on non-persistent platforms, that is, when a signal handler receives a signal that is bound to a handler, these platforms unbind the signal to default behavior before calling the handler. nonpersistent platforms—that is, platforms that, upon receiving a signal, reset the handler for the signal to SIG_DFL before calling the bound signal handler. Calling signal() under these conditions presents a race condition. (See SIG01-C. Understand implementation-specific details regarding signal handler persistence.)

A signal handler may only call signal() only if it does not need to be async asynchronous-safe (in other wordsthat is, if all relevant signals are masked , and it may therefore not so that the handler cannot be interrupted).)

...

Noncompliant Code Example

...

In this non-compliant code example, the signal handler handler() is bound to signum.

Code Block
bgColor#ffcccc

void handler(int signum) {
  signal(signum, handler);
  /* handling code */
}
/* ... */
signal(signum, handler);

(POSIX)

On nonpersistent platforms, this noncompliant code example Unfortunately this solution contains a race window, starting when the host environment resets the signal and ending when the handler calls signal(). During that time, a second signal sent to the program will trigger the default signal behavior, thereby consequently defeating the persistent behavior implied by the call to signal() from within the handler to reassert the binding.

If the environment is persistent (that is, it does not reset the handler when the signal is received), the signal() call from within the handler's signal() function is redundant.

Code Block
bgColor#ffcccc
langc
#include <signal.h>
 
void handler(int signum) {
  if (signal(signum, handler) == SIG_ERR) {
    /* Handle error */
  }
  /* Handle signal */
}
 
void func(void) {
  if (signal(SIGUSR1, handler) == SIG_ERR) {
    /* Handle error */
  }
}

Compliant Solution

...

(POSIX)

Calling the For persistent platforms, the handler's signal() function is unnecessary.from within the signal handler to reassert the binding is unnecessary for persistent platforms, as in this compliant solution:

Code Block
bgColor#ccccff
langc
#include <signal.h>
 
void handler(int signum) {
  /* handlingHandle codesignal */
}
/* ... */
signal(signum, handler);
 
void func(void) {
  if (signal(SIGUSR1, handler) == SIG_ERR) {
    /* Handle error */
  }
}

Compliant Solution (POSIX)

POSIX defines the sigaction(2) function, which assigns handlers to signals like in a similar manner to signal(2), but also allows one the caller to explicitly set persistence. One can thus use Consequently, the sigaction(2) and sidestep ) function can be used to eliminate the race window on non-persistent OS's.nonpersistent platforms, as in this compliant solution:

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include <stddef.h>
 
void handler(int signum) {
  /* handlingHandle codesignal */
}
/* ... */
/* Equivalent to signal( signum, handler);
   but make signal persistent */

void func(void) {
  struct sigaction act;
  act.sa_handler = handler;
  act.sa_flags = 0;
  if (sigemptyset( &act.sa_mask) != 0) {
    /* handleHandle error */
  }
  if (sigaction(signumSIGUSR1, &act, NULL) != 0) {
    /* handleHandle error */
  }
}

While Although the handler in this example does not call signal(), it safely can, since could do so safely because the signal is masked and so the handler can not cannot be interrupted. Note that if If the same handler is installed for more than one signal number, it would be necessary to mask the signals explicitly must be masked explicitly in act.sa_mask in order to ensure that the handler can not cannot be interrupted , since because the system masks only masks the signal being delivered.

In fact, POSIX recommends that new applications should use sigaction(2) and deprecates rather than signal(2). Unfortunately, The sigaction(2) function is not C99-compliant, defined by the C Standard and is not supported on some platforms, including Windows.

Compliant Solution (Windows)

There is no safe way to implement persistent signal-handler behavior on Windows platforms, and it should not be attempted. If a design depends on this behavior, and the design cannot be altered, it may be necessary to claim a deviation from this rule after completing an appropriate risk analysis.

The reason for this is that Windows is a nonpersistent platform as discussed above.  Just before calling the current handler function, Windows resets the handler for the next occurrence of the same signal to SIG_DFL. If the handler calls signal() to reinstall itself, there is still a race window. A signal might occur between the start of the handler and the call to signal(), which would invoke the default behavior instead of the desired handler.

Exceptions

SIG34-C-EX1: On a machine For implementations with persistent signal handlers, it is safe for a handler to modify the behavior for of its own signal. This would Behavior modifications include having ignoring the signal be ignored, reset resetting to the default behavior, or and having the signal handled by a different handler. A handler assigning itself to its own signal reasserting its binding is also safe , as it is a no-op. The handler is impervious to a race condition since multiple invocations of its signal will merely cause it to 'interrupt itself', until it manages to reassign its signal.but unnecessary.

The following code example resets a signal handler to the system's default behavior.:

Code Block
bgColor#ccccff
langc
#include <signal.h>
 
void handler(int signum) {
#ifndef WINDOWS#if !defined(_WIN32)
  if (signal(signum, SIG_DFL);
#endif
) == SIG_ERR) {
    /* handlingHandle codeerror */
  }
#endif
  /* Handle ...signal */
}
 
void func(void) {
  if (signal(signumSIGUSR1, handler);

...

 == SIG_ERR) {
    /* Handle error */
  }
}

Risk Assessment

Two signals in quick succession can trigger the a race condition on non-persistent nonpersistent platforms, thereby causing the signal's default behavior despite a handler's attempt to override it.

Recommendation

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SIG34-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
signal-handler-signal-callPartially checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-SIG34
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
BADFUNC.SIGNALUse of signal
Compass/ROSE

Can detect violations of this rule. However, false positives may occur on systems with persistent handlers
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-sig34-cFully implemented
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5021

C++5022


Klocwork
Include Page
Klocwork_V
Klocwork_V

MISRA.STDLIB.SIGNAL


LDRA tool suite
Include Page
LDRA_V
LDRA_V
97 DFully implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-SIG34-a

Properly define signal handlers
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

2762, 2763

Fully supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule SIG34-CChecks for signal call from within signal handler (rule partially covered)
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
signal-handler-signal-callPartially checked

Related Vulnerabilities

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

References

Wiki Markup
\[[ISO/IEC 9899-1999TR2|AA. C References#ISO/IEC 9899-1999]\] Section 7.14.1.1, "The {{signal}} function"

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT C Secure Coding StandardSIG01-C. Understand implementation-specific details regarding signal handler persistencePrior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961:2013Calling signal from interruptible signal handlers [sigcall]Prior to 2018-01-12: CERT: Unspecified Relationship


...

Image Added Image Added Image AddedSIG33-C. Do not recursively invoke the raise() function      12. Signals (SIG)       13. Error Handling with errno (ERR)