...
If your signal handler is not a plain old function, then the behavior of a call to it in response to a signal is implementation-defined, at best, and is likely to result in undefined behavior. All signal handlers must meet the definition of a plain old function. In particular, this definition prohibits use of features that exist in C++ but not in C (such as non-POD [non–plain old data] objects and exceptions), including indirect use of such features through function calls, and includes the restrictions placed on signal handlers in a C program. See Rule 11. Signals (SIG) for rules regarding conforming use of signals in a C program.
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 | ||||
---|---|---|---|---|
| ||||
#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. As a consequence of declaring the signal handler with C language linkage, the signal handler will have external linkage rather than internal linkage.
Code Block | ||||
---|---|---|---|---|
| ||||
#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 that allows exceptions, and it attempts to handle any exceptions thrown. 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 | ||||
---|---|---|---|---|
| ||||
#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 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 | ||||
---|---|---|---|---|
| ||||
#include <csignal> static void g() noexcept(false); // Not called extern "C" void sig_handler(int sig) { // Implement g()'s behavior to the extent possible given // 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 as a signal handler can result 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, the consequences that arise from failure to comply with this rule can range from benign (harmless) behavior to abnormal program termination, or even arbitrary code execution.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC56MSC54-CPP | High | Probable | High | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Parasoft C/C++test | 9.5 | MISRA2012-RULE-21_5_b |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C Coding Standard | SIG30-C. Call only asynchronous-safe functions within signal handlers SIG31-C. Do not access shared objects in signal handlers |
Bibliography
[ISO/IEC 14882-2014] | Subclause 18.10, "Other Runtime Support" |
...