Main Content

CERT C++: ERR56-CPP

Guarantee exception safety

Since R2022a

Description

Rule Definition

Guarantee exception safety1

Polyspace Implementation

The rule checker checks for Exception violating class invariant.

Examples

expand all

Issue

This defect occurs when a non-noexcept member function attempts to raise an exception after modifying any of the fields of the class. For instance, Polyspace® flags a throw() statement or a new statement if they are used after modifying the internal state of a class.

Risk

To facilitate recovery from an exception while preserving the invariant of the relevant objects, you must design programs to have exception safety. The C++ standard allows These levels of exception safety:

  • Basic Exception Safety: This level of exception safety requires that after raising an exception, the basic invariants of all objects are maintained in a valid state and no memory is leaked. If an operation has basic exception safety, then you can destroy or assign to an object after the operations, even if an exception has been raised. The operations in standard library offers at least basic exception safety.

  • Strong Exception Safety: This level of exception safety requires that after raising an exception, the state of the program remains as it was before the exception. Operations with strong exception safety either succeed or exit with an exception and have no effects on the program.

  • nothrow: This level of safety requires that an exception cannot occur in an operation.

Without at least the basic exception safety, exceptions might corrupt the state of a program, leave the program in an invalid state, or create memory leaks. Code that does not provide at least the basic exception safety guarantee is unsafe and defective.

Fix

To provide at least the basic exception safety in a function, modify the class invariant only when there can be no exceptions. When performing actions that might raise exceptions, use temporary objects that do not modify the original objects invariant.

Example
#include <cstdint>
#include <cstring>
template<typename T=int>
class myArray
{
public:
	myArray(){/*...*/}
	myArray(const myArray& rhs)
	{
		DeepCopyNC(rhs);    
	}
	~myArray()
	{
		delete[] array;
	}
	void DeepCopyNC(const myArray& rhs) // Noncompliant
	{
		if (this != &rhs) {
			delete[] array;
			array = nullptr; 
			len = rhs.len; 

			if (len > 0) {

				array = new T[len]; 
				std::memcpy(array, rhs.array, len * sizeof(T));
			}
		}
	}

private:
	T* array;
	std::size_t len;
};
extern 	myArray<> c1{};
void foo(){

	myArray<> c2{c1};
	
}

This example shows a generic class template myArray that manages a raw array. The copy constructor of this class shows two implementation of deep copy. In the function DeepCopyNC(), the memory operations are performed after modifying the this->array and this->len fields. If the memory operation exits with an exception, the invariant of the original class is violated. Because the class invariant is violated by an exception, the function DeepCopyNC() cannot guarantee basic exception safety. Polyspace flags it.

Correction

To guarantee basic exception safety, modify the class invariant only when the memory operation succeeds with no exceptions, as shown in DeepCopy.

#include <cstdint>
#include <cstring>
template<typename T=int>
class myArray
{
public:
	myArray(){/*...*/}
	myArray(const myArray& rhs)
	{
		DeepCopy(rhs); 
	}
	~myArray()
	{
		delete[] array;
	}
	void DeepCopy(const myArray& rhs) // Compliant
	{
		T* eTmp = nullptr;

		if (rhs.len > 0) {
			eTmp = new T[rhs.len]; 
			std::memcpy(eTmp, rhs.array, rhs.len * sizeof(T));
		}

		delete[] array;
		array = eTmp;
		len = rhs.len;
	}

private:
	T* array;
	std::size_t len;
};
extern 	myArray<> c1{};
void foo(){

	myArray<> c2{c1};
	
}

Check Information

Group: 08. Exceptions and Error Handling (ERR)

Version History

Introduced in R2022a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.