Not all exceptions can be caught, even with careful use of function-try-blocks. The C++ Standard, [except.handle], paragraph 13 [ISO/IEC 14882-2014], states the following:
Exceptions thrown in destructors of objects with static storage duration or in constructors of namespace scope objects with static storage duration are not caught by a function-try-block on
main()
. Exceptions thrown in destructors of objects with thread storage duration or in constructors of namespace-scope objects with thread storage duration are not caught by a function-try-block on the initial function of the thread.
When declaring an object with static or thread storage duration, and that object is not declared within a function block scope, the type's constructor must be declared noexcept
and must comply with ERR55-CPP. Honor exception specifications. Additionally, the initializer for such a declaration, if any, must not throw an uncaught exception (including from any implicitly - constructed objects that are created as a part of the initialization). If an uncaught exception is thrown before main()
is executed, or if an uncaught exception is thrown after main()
has finished executing, there are no further opportunities to handle the exception and it results in implementation-defined behavior; see . (See ERR50-CPP. Do not abruptly terminate the program for further details.)
For more information on exception specifications of destructors, see DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions.
...
In this noncompliant example, the constructor of global
may throw an exception during program startup. (the The std::string
constructor accepting , which accepts a const char *
and a default allocator object, is not marked noexcept
and consequently allows all exceptions.) . This exception is not caught by the function-try-block on main()
, resulting in a call to std::terminate()
and abnormal program termination.
...
Compliant code must prevent exceptions from escaping during program startup and termination. This compliant solution avoids defining a std::string
at global namespace scope and instead uses a static const char *
:.
Code Block | ||||
---|---|---|---|---|
| ||||
static const char *global = "..."; int main() { // ... } |
...
Throwing an exception that cannot be caught results in abnormal program termination and can lead to denial-of-service attacks.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ERR58-CPP | Low | Likely | Low | P9 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| potentially-throwing-static-initialization | Partially checked | ||||||
Axivion Bauhaus Suite |
| CertC++-ERR58 | |||||||
Clang |
| cert-err58-cpp | Checked by clang-tidy | ||||||
CodeSonar |
| LANG.STRUCT.EXCP.THROW | Use of throw | ||||||
Helix QAC |
| C++4634, C++4636, C++4637, C++4639 | |||||||
Parasoft C/C++test |
| CERT_CPP-ERR58-a | Exceptions shall be raised only after start-up and before termination of the program | |||||||
Polyspace Bug Finder |
| CERT C++: ERR58-CPP | Checks for exceptions raised during program startup (rule fully covered) | ||||||
RuleChecker |
| potentially-throwing-static-initialization | Partially checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
This rule is a subset of ERR50-CPP. Do not abruptly terminate the program
SEI CERT C++ Coding Standard | DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions ERR55-CPP. Honor exception specifications |
Bibliography
[ISO/IEC 14882-2014] | Subclause 15.4, "Exception Specifications" |
[Sutter |
2000] | Item 8, "Writing Exception-Safe Code—Part 1" |
...
...