According to the C++ Standard, [except.spec] paragraph 8 [ISO/IEC 14882-2014]:
A function is said to allow an exception of type
E
if the constant-expression in its noexcept-specification evaluates tofalse
or its dynamic-exception-specification contains a typeT
for which a handler of typeT
would 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- declared with an exception-specification throws an exception of a type that would not included in match the exception-specification, the function std::unexpected()
is called. The behavior of this function can be overridden within a project, 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 will be called, leading declared with a noexcept-specification throws an exception of a type that would lead to 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 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 listed in its exception-specification.
...
Noncompliant Code Example
In this non-compliant noncompliant code example, the second function claims to throw only exception1
, but it may also throw exception2
.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <exception> class exception1 : public std::exception {}; class exception2 : public std::exception {}; void foo() { throw exception2; // ok...OK, since foo() promises nothing wrt exceptions } void bar() throw (exception1) { foo(); // badBad, since foo() can throw exception2 } |
Compliant Solution
A simple This compliant solution is to catch any catches the exceptions thrown by foo{}by foo()
:
Code Block | ||||
---|---|---|---|---|
| ||||
void bar() throw (exception1) { try { foo(); } catch (...exception2 e) { // handle error, without re-throwing it. } } |
Compliant Solution
This compliant solution declares an exception-specification for bar()
which covers all of the exceptions that can be thrown from it:
Code Block | ||||
---|---|---|---|---|
| ||||
void bar() throw (exception1, exception2) { foo(); } |
Noncompliant Code Example
In this noncompliant code example, a function is declared as non-throwing, but it is possible for std::vector::resize()
to throw an exception when the requested memory cannot be allocated:
Code Block | ||||
---|---|---|---|---|
| ||||
#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:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <vector>
void f(std::vector<int> &v, size_t s) {
v.resize(s); // May throw, but that is OK.
} |
Implementation Details
Some vendors provide language extensions for specifying whether a function throws or not. For instance, Microsoft Visual Studio provides __declspec(nothrow))
, and Clang supports __attribute__((nothrow))
. Currently, the vendors do not document the behavior of specifying a nonthrowing function using these extensions. It is presumed that it is undefined behavior when throwing from a function declared with one of these language extensions.
Risk Assessment
Throwing unexpected exceptions disrupts control flow and can cause premature termination and denial of service.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ERR37-CPP | low Low | likely Likely | low Low | P9 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[ISO/IEC 14882-2014] | 15.4, "Exception Specifications" |
[MSDN] | nothrow (C++) |
[GNU] | Declaring Attributes of Functions |
2003]
[MISRA 08] Rule 15-5-2
ERR36-CPP. Multiple catch handlers to a try block should order their exceptions from most derived to most basic 12012. Exceptions and Error Handling (ERR) ERR38-CPP. Deallocation functions must not throw exceptions