CertC++-ERR51¶
Handle all exceptions
Required inputs: IR, StaticSemanticAnalysis
When an exception is thrown, control is transferred to the nearest handler with a type that matches the type of the exception thrown. If no matching handler is directly found within the handlers for a try block in which the exception is thrown, the search for a matching handler continues to dynamically search for handlers in the surrounding try blocks of the same thread. The C++ Standard, [except.handle], paragraph 9 [ ISO/IEC 14882-2014], states the following:
If no matching handler is found, the function
std::terminate()is called; whether or not the stack is unwound before this call tostd::terminate()is implementation-defined.
The default terminate handler called by
std::terminate() calls
std::abort(), which
abnormally
terminates the process. When
std::abort() is called, or if the
implementation
does not unwind the stack prior to calling
std::terminate(), destructors for objects may not be called
and external resources can be left in an indeterminate
state. Abnormal process termination is the typical vector for
denial-of-service attacks.
For more information on implicitly calling
std::terminate(), see
ERR50-CPP.
Do not abruptly terminate the program.
All exceptions thrown by an application must be caught by a matching exception handler. Even if the exception cannot be gracefully recovered from, using the matching exception handler ensures that the stack will be properly unwound and provides an opportunity to gracefully manage external resources before terminating the process.
As per ERR50-CPP-EX1, a program that encounters an
unrecoverable exception may explicitly catch the exception and terminate, but
it may not allow the exception to remain uncaught. One possible solution
to comply with this rule, as well as with ERR50-CPP, is for the
main() function to catch all exceptions. While this does not
generally allow the application to recover from the exception gracefully, it
does allow the application to terminate in a controlled fashion.
Noncompliant Code Example
In this noncompliant code example, neither
f() nor
main() catch exceptions thrown by
throwing_func(). Because no matching handler can be found for the
exception thrown,
std::terminate() is called.
void throwing_func() noexcept(false);
void f() {
throwing_func();
}
int main() {
f();
}
Compliant Solution
In this compliant solution, the main entry point handles all exceptions,
which ensures that the stack is unwound up to the
main() function and allows for graceful management of external
resources.
void throwing_func() noexcept(false);
void f() {
throwing_func();
}
int main() {
try {
f();
} catch (...) {
// Handle error
}
}
Noncompliant Code Example
In this noncompliant code example, the thread entry point function
thread_start() does not catch exceptions thrown by
throwing_func(). If the initial thread function exits because an
exception is thrown,
std::terminate() is called.
#include <thread>
void throwing_func() noexcept(false);
void thread_start() {
throwing_func();
}
void f() {
std::thread t(thread_start);
t.join();
}
Compliant Solution
In this compliant solution, the
thread_start() handles all exceptions and does not rethrow,
allowing the thread to terminate normally.
#include <thread>
void throwing_func() noexcept(false);
void thread_start(void) {
try {
throwing_func();
} catch (...) {
// Handle error
}
}
void f() {
std::thread t(thread_start);
t.join();
}
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 |
|---|---|---|---|---|---|
| ERR51-CPP | Low | Probable | Medium | P4 | L3 |
Related Guidelines
This rule is a subset of ERR50-CPP. Do not abruptly terminate the program.
| MITRE CWE | CWE-754, Improper Check for Unusual or Exceptional Conditions |
Bibliography
| [ ISO/IEC 14882-2014] | Subclause 15.1, "Throwing an Exception" Subclause 15.3, "Handling an Exception" Subclause 15.5.1, "The std::terminate() Function"
|
| [ MISRA 2008] | Rule 15-3-2 (Advisory) Rule 15-3-4 (Required) |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
exception_escaping_main |
Uncaught exception escaping from main or additional entry point |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
exclude_exception_base_classes¶
exclude_exception_base_classes : set[bauhaus.analysis.config.QualifiedName] = set()
generate_violation_path¶
generate_violation_path : bool = True
inspect_at_exit_handlers¶
inspect_at_exit_handlers : bool = True
at_exit() handlers-functions.
inspect_atexit_entry_points¶
inspect_atexit_entry_points : bool = False
inspect_thread_main¶
inspect_thread_main : bool = True