Versions Compared

Key

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

When an exception is thrown, the value of the object in the throw expression is used to initialize an anonymous temporary object called the exception object. The type of this exception object is used to transfer control to the nearest catch handler which handler, which contains an exception declaration with a matching type. The C++ Standard, [except.handle], paragraph 16 [ISO/IEC 14882-2014], in part, states , in partthe following:

The variable declared by the exception-declaration, of type cv T or cv T&, is initialized from the exception object, of type E, as follows:
  — if T is a base class of E, the variable is copy-initialized from the corresponding base class subobject of the exception object;
  — otherwise, the variable is copy-initialized from the exception object.

Because the variable declared by the exception-declaration is copy-initialized, it is possible to slice the exception object as part of the copy operation, losing valuable exception information and leading to incorrect error recovery. For instance, all exception types provided by the Standard Template Library inherit from std::exception, which has a virtual member function, what(), that returns implementation-defined information about the exception object. If the exception variable declared by the catch handler was sliced from the exception object created by the throw expression, calling what() on the catch handler exception variable would not result in calling what() on the exception object. For more information about object slicing, see OOP51-CPP. Do not slice derived objects. For more information about object slicing, see OOP51-CPP. Do not slice derived objects. Further, if the copy constructor of the exception object throws an exception, the copy initialization of the exception-declaration object results in undefined behavior. (See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.)

Always catch exceptions by lvalue reference unless the type is a trivial type. For reference, the C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], defines trivial types as the following:

Arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of these types are collectively called scalar types.... Scalar types, trivial class types, arrays of such types and cv-qualified versions of these types are collectively called trivial types.

The C++ Standard, [class], paragraph 6, defines trivial class types as the following:

A trivially copyable class is a class that:
  — has no non-trivial copy constructors,
  — has no non-trivial move constructors,
  — has no non-trivial copy assignment operators,
  — has no non-trivial move assignment operators, and
  — has a trivial destructor.
A trivial class is a class that has a default constructor, has no non-trivial default constructors, and is trivially copyable. [Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — end note]

...

In this noncompliant code example, an object of type S is used to initialize the exception object that is later caught by an exception-declaration of type std::exception. The exception-declaration matches the exception object type, and so the variable E is copy-initialized from the exception object, resulting in the exception object being sliced. Consequently, the output of this noncompliant code example is the implementation-defined value returned from calling std::exception::what() instead of "My custom exception".

...

Object slicing can result in abnormal program execution. This generally is not a problem for exceptions, but it can lead to unexpected behavior depending on the assumptions made by the exception handler.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR61-CPP

Low

Unlikely

Low

P3

L3

Automated Detection

Tool

Version

Checker

Description

Astrée

Include Page
Astrée_V
Astrée_V

catch-class-by-value
Fully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC++-ERR61

Clang

Include Page
Clang_38_V
Clang_38_V

cert-err61-cpp

Checked by clang-tidy; also checks for VOID ERR09-CPP. Throw anonymous temporaries by default
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.STRUCT.EXCP.CATCH

LANG.STRUCT.EXCP.THROW

Use of catch

Use of throw

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++4031 
Klocwork
Include Page
Klocwork_V
Klocwork_V

MISRA.CATCH.BY_VALUE


LDRA tool suite
Include Page
LDRA_V
LDRA_V

455 S

Fully implemented

Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_CPP-ERR61-a
CERT_CPP-ERR61-b

A class type exception shall always be caught by reference
Throw by value, catch by reference

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: ERR61-CPPChecks for exception object initialized by copy in catch statement (rule fully covered)
PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V746V816

RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
catch-class-by-value
Fully checked
SonarQube C/C++ Plugin
Include Page
SonarQube C/C++ Plugin_V
SonarQube C/C++ Plugin_V
S1044
 

Related Vulnerabilities

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

Related Guidelines

This rule is a subset of OOP51-CPP. Do not slice derived objects.

Bibliography

[ISO/IEC 14882-2014]

Subclause 3.9, "Types"
Clause 9, "Classes"
Subclause 15.1, "Throwing an Exception"
Subclause 15.3, "Handling an Exception" 

[MISRA
08
2008]Rule 15-3-5

...


...

Image Modified Image Modified