The std::abort()
, std::quick_exit()
, 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 How a system manages open streams when a program ends is implementation-defined as to whether open [ISO/IEC 9899:1999]. Open streams with unwritten buffered data are may or may not be flushed, open streams are may or may not be closed, or temporary files are removed [ISO/IEC 9899:1999]. Because and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should only be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)
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]:
- When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception
...
- ([except.throw], paragraph 7)
- See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
- When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled
...
- ([except.throw], paragraph 9)
- When the exception handling mechanism cannot find a handler for a thrown
...
- exception ([except.handle], paragraph 9)
- See ERR51-CPP. Handle all exceptions for more information.
- When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception
...
- ([except.spec], paragraph 9)
- See
...
- ERR55-CPP. Honor exception specifications for more information.
- When the destruction of an object during stack unwinding terminates by throwing an exception
...
- ([except.ctor], paragraph 3)
- See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
- When initialization of a
...
- nonlocal variable with static or thread storage duration exits via an exception
...
- ([basic.start.init], paragraph 6)
- See
...
...
- Handle all exceptions thrown before main() begins executing for more information.
- When destruction of an object with static or thread storage duration exits via an exception
...
- ([basic.start.term], paragraph 1)
- See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
- When execution of a function registered with
std::atexit()
...
- or
std::at_quick_exit()
exits via an exception
...
- ([support.start.term], paragraphs 8 and 12)
- When the implementation’s default unexpected exception handler is called
...
- ([except.unexpected], paragraph 2)
Note thatstd::unexpected()
is currently deprecated
...
- .
- When
std::unexpected()
throws an exception
...
- that 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)
- When the function
std::nested_exception::rethrow_nested()
is called for an object that has captured no exception
...
- ([except.nested], paragraph 4)
- When execution of the initial function of a thread exits via an exception
...
- ([thread.thread.constr], paragraph 5)
- See ERR51-CPP. Handle all exceptions for more information.
- When the destructor is invoked on an object of type
std::thread
that refers to a joinable thread
...
- ([thread.thread.destr], paragraph 1)
- When the copy assignment operator is invoked on an object of type
std::thread
that refers to a joinable thread
...
- ([thread.thread.assign], paragraph 1)
- When calling
condition_variable::wait()
,condition_variable::wait_until()
, orcondition_variable::wait_for()
results in a failure to meet the
...
- postcondition:
lock.owns_lock() == true
orlock.mutex()
is not locked by the calling thread
...
- ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
- When calling
condition_variable_any::wait()
,condition_variable_any::wait_until()
, orcondition_variable_any::wait_for()
results in a failure to meet the
...
- postcondition:
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 an implicit call to std::terminate()
, and in a few cases, it is implementation-defined as to whether or not stack unwinding will occur or not. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states , in partthe following:
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 allow an implicit call to explicitly or implicitly call std::quick_exit()
, 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 allow an implicit call to explicitly or implicitly call std::terminate()
. Abnormal Abnormal process termination is the typical vector for denial-of-service attacksattacks.It is acceptable to call
The 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. See also ERR04-CPP. Choose an appropriate termination strategy.exit()
function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:
Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.
You may call std::exit()
only in a program that has not yet initialized any objects with automatic storage duration.
Noncompliant Code Example
In this noncompliant code example, the call to C::to f()
may result in an exception being thrown. Since C::f()
is called from a destructor, this can , which was registered as an exit handler with std::at_exit()
, may result in a call to std::terminate()
if a non-local object of type C
has static or thread storage duration, or if an object of type C
is destroyed during stack unwinding (as in this example) because throwing_func()
may throw an exception.
Code Block | ||||
---|---|---|---|---|
| ||||
class C { void f#include <cstdlib> void throwing_func() noexcept(false); public: ~Cvoid f() { f(); } }; void throwing_func() noexcept(false); void f() noexcept(false) { C c;// Not invoked by the program except as an exit handler. throwing_func(); } voidint gmain() noexcept(true) { tryif { (0 f(); } catch (...!= std::atexit(f)) { // Handle error } } |
If throwing_func()
throws an exception, f()
does not attempt to catch it and it will be handled by g()
. However, during stack unwinding to reach the exception handler in g()
, the automatic local variable c
will be destroyed, resulting in a call to C::~C()
. When the destructor attempts to throw an exception, std::terminate()
will be called instead of throwing.
Note, the declaration for C::~C()
does not comply with DCL40-CPP. Destructors and deallocation functions must be declared noexcept because destructors are implicitly declared noexcept(true)
, and this destructor allows exceptions by virtue of calling a function marked noexcept(false)
.
// ...
} |
Compliant Solution
In this compliant solution, the destructor for C
f()
handles all exceptions and does not rethrow. When the automatic local variable c
is destroyed, no exception is triggered from the C::~C()
call, and the exception thrown by throwing_func()
will be caught by the handler in g()
and does not rethrow.
Code Block | ||||
---|---|---|---|---|
| ||||
class C { void f#include <cstdlib> void throwing_func() noexcept(false); public: void ~Cf() { // Not invoked by the program except as an exit handler. try { fthrowing_func(); } catch (...) { // Handle error } } }; void throwing_funcint main() noexcept(false); void f() noexcept(false) { C c; throwing_func(); } void g() noexcept(trueif (0 != std::atexit(f)) { try { // Handle f();error } catch (...) { // Handle error }... } |
Noncompliant Code Example
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.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:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstdlib><exception> void throwing_func(report(const char *msg) noexcept(false); [[noreturn]] void f(fast_fail(const char *msg) { throwing_func(); } int main() { if (0 != std::at_exit(f)) { // Handle error } // ... } |
Compliant Solution
In this compliant solution, f()
handles all exceptions thrown by throwing_func()
, and does not rethrow:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstdlib> void throwing_func// Report error message to operator report(msg); // Terminate std::terminate(); } void critical_function_that_fails() noexcept(false); void f() { try { throwing_funccritical_function_that_fails(); } catch (...) { // Handle errorfast_fail("Critical function failure"); } } int main() { if (0 != std::at_exit(f)) { // Handle error } // ... } |
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 in an implicit manner can lead to resources not being freed, closed, etcand 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 |
---|
4037, 4038, 4636, 4637
Astrée |
| stdlib-use | Partially checked | ||||||
CodeSonar |
| BADFUNC.ABORT | Use of abort | ||||||
Helix QAC |
| C++5014 | |||||||
Klocwork |
| MISRA.TERMINATE CERT.ERR.ABRUPT_TERM | |||||||
LDRA tool suite |
| 122 S | Enhanced Enforcement | ||||||
Parasoft C/C++test |
| CERT_CPP-ERR50-a | The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception | ||||||
Polyspace Bug Finder |
| CERT C++: ERR50-CPP | Checks for implicit call to terminate() function (rule partially covered) | ||||||
PVS-Studio |
| V667, V2014 | |||||||
RuleChecker |
| stdlib-use | Partially checked | ||||||
SonarQube C/C++ Plugin |
| S990 |
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 |
Do not let exceptions escape from destructors or deallocation functions | |
MITRE CWE | CWE-754, Improper Check for Unusual or Exceptional Conditions |
DCL40-CPP. Destructors and deallocation functions must be declared noexcept
Bibliography
[ISO/IEC |
9899- |
2011] |
Subclause 7.20.4.1, "The |
std::terminate()
abort Function" |
Subclause 7.20.4.4, "The _Exit Function" |
[ISO/IEC |
14882-2014] |
Subclause 15.5.1, "The |
abort
|
_Exit
Function"Subclause 18.5, "Start and Termination" |
[MISRA |
2008] | Rule 15-3-2 |
(Advisory) Rule 15-3-4 |
...
(Required) |
...