CertC++-ERR55¶
Honor exception specifications
Required inputs: IR, StaticSemanticAnalysis
The C++ Standard, [except.spec], paragraph 8 [ ISO/IEC 14882-2014], states the following:
A function is said to allow an exception of type
Eif the constant-expression in its noexcept-specification evaluates tofalseor its dynamic-exception-specification contains a typeTfor which a handler of typeTwould be a match (15.3) for an exception of typeE.
If a function throws an exception other than one allowed by its exception-specification, it can lead to an implementation-defined termination of the program ([except.spec], paragraph 9).
If a function declared with a dynamic-exception-specification throws
an exception of a type that would not match the
exception-specification, the function
std::unexpected() is called. The behavior of this function can be
overridden but, by default, causes an exception of
std::bad_exception to be thrown. Unless
std::bad_exception is listed in the
exception-specification, the function
std::terminate() will be called.
Similarly, if a function declared with a noexcept-specification throws
an exception of a type that would cause the noexcept-specification to
evaluate to
false, the function
std::terminate() will be called.
Calling
std::terminate() leads to implementation-defined termination of
the program. To prevent
abnormal
termination of the program, any function that declares an
exception-specification should restrict itself, as well as any
functions it calls, to throwing only allowed exceptions.
Noncompliant Code Example
In this noncompliant code example, a function is declared as nonthrowing, but
it is possible for
std::vector::resize() to throw an exception when the
requested memory cannot be allocated.
#include <cstddef>
#include <vector>
void f(std::vector<int> &v, size_t s) noexcept(true) {
v.resize(s); // May throw
}
Compliant Solution
In this compliant solution, the function's noexcept-specification is removed, signifying that the function allows all exceptions.
#include <cstddef>
#include <vector>
void f(std::vector<int> &v, size_t s) {
v.resize(s); // May throw, but that is okay
}
Noncompliant Code Example
In this noncompliant code example, the second function claims to throw only
Exception1, but it may also throw
Exception2.
#include <exception>
class Exception1 : public std::exception {};
class Exception2 : public std::exception {};
void foo() {
throw Exception2{}; // Okay because foo() promises nothing about exceptions
}
void bar() throw (Exception1) {
foo(); // Bad because foo() can throw Exception2
}
Compliant Solution
This compliant solution catches the exceptions thrown by
foo().
#include <exception>
class Exception1 : public std::exception {};
class Exception2 : public std::exception {};
void foo() {
throw Exception2{}; // Okay because foo() promises nothing about exceptions
}
void bar() throw (Exception1) {
try {
foo();
} catch (Exception2 e) {
// Handle error without rethrowing it
}
}
Compliant Solution
This compliant solution declares a
dynamic exception-specification for
bar(), which covers all of the exceptions that can be thrown from
it.
#include <exception>
class Exception1 : public std::exception {};
class Exception2 : public std::exception {};
void foo() {
throw Exception2{}; // Okay because foo() promises nothing about exceptions
}
void bar() throw (Exception1, Exception2) {
foo();
}
Implementation Details
Some vendors provide language extensions for specifying whether or not a
function throws. For instance,
Microsoft
Visual Studio provides
__declspec(nothrow)), and
Clangsupports
__attribute__((nothrow)). Currently, the vendors do not document
the behavior of specifying a nonthrowing function using these extensions.
Throwing from a function declared with one of these language extensions is
presumed to be
undefined
behavior.
Risk Assessment
Throwing unexpected exceptions disrupts control flow and can cause premature termination and denial of service.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| ERR55-CPP | Low | Likely | Low | P9 | L2 |
Related Guidelines
| SEI CERT C++ Coding Standard | ERR50-CPP. Do not abruptly terminate the program |
Bibliography
| [ GNU 2016] | "Declaring Attributes of Functions" |
| [ ISO/IEC 14882-2014] | Subclause 15.4, "Exception Specifications" |
| [ MSDN 2016] | "
nothrow (C++)"
|
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
exception_specification_violation |
Exception violates function’s exception-specification. |
None |
False |
exception_specification_violation_from_call |
Exceptions propagated from this call violate function’s exception-specification. |
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
ignore_constructor_destructor¶
ignore_constructor_destructor : bool = False
ignore_unknown_routines¶
ignore_unknown_routines : bool = False