Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

When an exception is thrown, the exception object operand of the throw expression is copied into a temporary object that is used to initialize the handler. The C++ Standard, [except.throw], paragraph 3 [ISO/IEC 14882-2014], states in part, states the following:

Throwing an exception copy-initializes a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler.

If the copy constructor for the exception object type throws during the copy initialization, std::terminate() is called, which can result in undefined possibly unexpected implementation-defined behavior. For more information on implicitly calling std::terminate(), see ERR50-CPP. Do not abruptly terminate the program.

The copy constructor for an object thrown as an exception must be declared noexcept, including any implicitly-defined copy constructors. Note, any  Any function declared noexcept that terminates by throwing an exception does not conform to violates ERR55-CPP. Honor exception specifications.

...

In this noncompliant code example, an exception of type S is thrown from in f(). However, because S has a std::string data member, and the copy constructor for std::string is not declared noexcept, the implicitly-defined copy constructor for S is also not declared to be noexcept. In low-memory situations, the copy constructor for std::string may be unable to allocate sufficient memory to complete the copy operation, resulting in a std::bad_alloc exception being thrown.

...

This compliant solution assumes that the type of the exception object can inherit from std::runtime_error, or that type can be used directly.  Unlike std::string, a std::runtime_error object is already required to correctly handle an arbitrary-length error message that is exception safe and guarantees the copy constructor will not throw : [ ISO/IEC 14882-2014 ].

Code Block
bgColor#ccccff
langcpp
#include <stdexcept>
#include <type_traits>

struct S : std::runtime_error {
  S(const char *msg) : std::runtime_error(msg) {}
};
 
static_assert(std::is_nothrow_copy_constructible<S>::value,
              "S must be nothrow copy constructible");

void g() {
  // If some condition doesn't hold...
  throw S("Condition did not hold");
}

void f() {
  try {
    g();
  } catch (S &s) {
    // Handle error
  }
}

Compliant Solution

If the exception type cannot be modified to inherit from std::runtime_error, a data member of that type is an unexpected but a legitimate implementation strategy, as shown in this compliant solution:.

Code Block
bgColor#ccccff
langcpp
#include <stdexcept>
#include <type_traits>

class S : public std::exception {
  std::runtime_error m;
public:
  S(const char *msg) : m(msg) {}
  
  const char *what() const noexcept override {
    return m.what();   
  }
};
 
static_assert(std::is_nothrow_copy_constructible<S>::value,
              "S must be nothrow copy constructible");
 
void g() {
  // If some condition doesn't hold...
  throw S("Condition did not hold");
}

void f() {
  try {
    g();
  } catch (S &s) {
    // Handle error
  }
}

...

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

ERR60-CPP

Low

Probable

Medium

P4

L3

Automated Detection

Tool

Version

Checker

Description

Clang
Include Page
Clang_38_V
Clang_38_V
cert-err60-cppChecked by clang-tidy
PRQA QA-
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++
Include Page
3508
Parasoft C/
PRQA QA-
C++test

Include Page
Parasoft_V
Parasoft_V

PRQA QA-C++_V

3508

 

CERT_CPP-ERR60-a
CERT_CPP-ERR60-b

Exception objects must be nothrow copy constructible
An explicitly declared copy constructor for a class that inherits from 'std::exception' should have a non-throwing exception specification

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: ERR60-CPP

Checks for throwing exception object in copy constructor (rule fully covered)

Related Vulnerabilities

Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[ Hinnant 2015 ]
 

[ISO/IEC 14882-2014]

Subclause 15.1, "Throwing an Exception"
Subclause 18.8.1, "Class exception"
Subclause 18.8.5, "Exception Propagation"

...


...

  Image Modified