The std::abort() and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed [ISO/IEC 9899:1999] is implementation defined. Because these functions can leave external resources in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application.

The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

In many circumstances, the call stack will not be unwound in response to the implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], states, in part:

In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

Do not explicitly or implicitly call std::abort() or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate()Abnormal process termination is the typical vector for denial-of-service attacks.

Noncompliant Code Example

In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception:

#include <cstdlib>
 
void throwing_func() noexcept(false);
 
void f() {
  throwing_func();
}
 
int main() {
  if (0 != std::atexit(f)) {
    // Handle error
  }
  // ...
}

Compliant Solution

In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow:

#include <cstdlib>

void throwing_func() noexcept(false);

void f() {
  try {
    throwing_func();
  } catch (...) {
    // Handle error
  }
}

int main() {
  if (0 != std::atexit(f)) {
    // Handle error
  }
  // ...
}

Exceptions

ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort()std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example:

#include <exception>

void report(const char *msg) noexcept;
[[noreturn]] void fast_fail(const char *msg) {
  // Report error message to operator
  report(msg);
 
  // Terminate
  std::terminate();
}
 
void critical_function_that_fails() noexcept(false);
 
void f() {
  try {
    critical_function_that_fails();
  } catch (...) {
    fast_fail("Critical function failure");
  }
}

Note that the assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

Risk Assessment

Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR50-CPP

Low

Probable

Medium

P4

L3

Automated Detection

Tool

Version

Checker

Description

PRQA QA-C++

4037, 4038, 4636, 4637

 

Related Vulnerabilities

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

Related Guidelines

SEI CERT C++ Coding Standard

ERR51-CPP. Handle all exceptions
ERR37-CPP. Honor exception specifications
ERR41-CPP. Constructors of objects with static or thread storage duration must not throw exceptions
DCL58-CPP. Destructors and deallocation functions must be declared noexcept

MITRE CWECWE-754, Improper Check for Unusual or Exceptional Conditions

Bibliography

[ISO/IEC 9899:1999]Subclause 7.20.4.1, "The abort Function"
Subclause 7.20.4.4, "The _Exit Function"
[ISO/IEC 14882-2014]

Subclause 15.5.1, "The std::terminate() Function"
Subclause 18.5, "Start and Termination" 

[MISRA 08]Rule 15-3-2 (Advisory)
Rule 15-3-4 (Required)