Versions Compared

Key

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

...

In particular, a signal handler using exception handling is very likely to have problems. Also, invoking std::exit may cause destruction of objects, including those of the standard library implementation, which, in general, yields undefined behavior in a signal handler.

...

Noncompliant Code Example

In this noncompliant code example, the signal handler is declared as a static function. However, since all signal handler functions must have C language linkage, and C++ is the default language linkage for functions in C++, calling the signal handler results in undefined behavior.

Code Block
bgColor#FFcccc
langcpp
#include <csignal>
 
static void sig_handler(int sig) {
  // Implementation details elided.
}

void f() {
  if (SIG_ERR == std::signal(SIGTERM, sig_handler)) {
    // Handle error
  }
}

Compliant Solution

This compliant solution defines sig_handler() as having C language linkage. Note that this solution requires all signal handler functions to be declared with external linkage instead of internal linkage.

Code Block
bgColor#ccccff
langcpp
#include <csignal>
 
extern "C" void sig_handler(int sig) {
  // Implementation details elided.
}

void f() {
  if (SIG_ERR == std::signal(SIGTERM, sig_handler)) {
    // Handle error
  }
}

Noncompliant Code Example

In this noncompliant code example, a signal handler calls a function which that allows exceptions, and it attempts to handle any exceptions thrown. Since Because exceptions are not part of the common subset of C and C++ features, this example results in implementation-defined behavior. However, it is unlikely that the implementation's behavior will be suitable. For instance, on a stack-based architecture where a signal is generated asynchronously (instead of as a result of a call to std:abort() or std::raise()), it is possible that the stack frame is not properly initialized, causing stack tracing to be unreliable , and preventing the exception from being caught properly.

Code Block
bgColor#FFcccc
langcpp
#include <csignal>

static void g() noexcept(false);

extern "C" void sig_handler(int sig) {
  try {
    g();
  } catch (...) {
    // Handle error
  }
}
 
void f() {
  if (SIG_ERR == std::signal(SIGTERM, sig_handler)) {
    // Handle error
  }
}

Compliant Solution

There is no compliant solution where whereby g() can be called because it allows exceptions. Even if g() were implemented such that it handled all exceptions and was marked noexcept(true), it would still be noncompliant to call it from a signal handler because g() would still use a feature that is not a part of the common subset of C and C++ features allowed by a signal handler. Therefore, this compliant solution removes the call to g():

Code Block
bgColor#ccccff
langcpp
#include <csignal>

static void g() noexcept(false); // Not called

extern "C" void sig_handler(int sig) {
  // Implement g()'s behavior asto bestthe asextent possible given the
  // the constraints placed on a signal handler function.
}

void f() {
  if (SIG_ERR == std::signal(SIGTERM, sig_handler)) {
    // Handle error
  }
}

Risk Assessment

Failing to use a Plain Old Function plain old function as a signal handler can result in in implementation-defined behavior as well as undefined behavior. Given the number of features that exist in C++ that do not also exist in C, failure to comply with this rule can have benign consequences, abnormal program termination, or possibly even arbitrary code execution.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MSC56-CPP

Medium

Probable

High

P4

L3

Automated Detection

Tool

Version

Checker

Description

    

Related Vulnerabilities

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

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]

18.10, "Other Runtime Support"

 

...