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. It is implementation-defined as to whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed [ISO/IEC 9899:1999]. Because these functions can leave external resources in an indeterminate state, they should only be called explicitly 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]:
std::atexit()
or std::at_quick_exit()
exits via an exception. ([support.start.term], paragraphs 8 and 12)std::unexpected()
is currently deprecated.std::unexpected()
throws an exception which is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception()
is not included in that dynamic-exception-specification. ([except.unexpected], paragraph 3)std::nested_exception::rethrow_nested()
is called for an object that has captured no exception. ([except.nested], paragraph 4)std::thread
that refers to a joinable thread. ([thread.thread.destr], paragraph 1)std::thread
that refers to a joinable thread. ([thread.thread.assign], paragraph 1)condition_variable::wait()
, condition_variable::wait_until()
, or condition_variable::wait_for()
results in a failure to meet the post-condition: lock.owns_lock() == true
or lock.mutex()
is not locked by the calling thread. ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)condition_variable_any::wait()
, condition_variable_any::wait_until()
, or condition_variable_any::wait_for()
results in a failure to meet the post-condition: lock
is not locked by the calling thread. ([thread.condition.condvarany], paragraphs 11, 16, and 22)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 as to whether stack unwinding will occur or not. 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 beforestd::terminate()
is called. In all other situations, the stack shall not be unwound beforestd::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 } // ... } |
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 } // ... } |
ERR30-CPP-EX1: It is acceptable to explicitly call std::abort()
, std::_Exit()
, or std::terminate()
in response to a critical program error for which no recovery is possible, after indicating the nature of the problem to the operator, 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, as failed assertions will notify the operator on the standard error stream in an implementation-defined manner prior to calling std::abort()
.
Allowing the application to abnormally terminate can lead to resources not being freed, closed, etc. It is frequently a vector for denial-of-service attacks.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ERR50-CPP | Low | Probable | Medium | P4 | L3 |
Tool | Version | Checker | Description |
---|---|---|---|
4037, 4038, 4636, 4637 |
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
[ISO/IEC 14882-2014] | 15.5.1, "The |
[ISO/IEC 9899:1999] | 7.20.4.1, "The abort Function"7.20.4.4, "The _Exit Function" |
[MISRA 08] | Rule 15-3-2, "There should be at least one exception handler to catch all otherwise unhandled exceptions" Rule 15-3-4, "Each exception explicitly thrown in the code shall have a handler of a compatible type in all call paths that could lead to that point" |