Versions Compared

Key

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

Reclaiming resources when exceptions are thrown is important. An exception being thrown may result in cleanup code being bypassed or an object being left in a partially initialized state. Such a partially - initialized object would violate basic exception safety, as described in ERR56-CPP. Guarantee exception safety. It is preferable that resources be reclaimed automatically, using the RAII design pattern [Stroustrup 2001], when objects go out of scope. This technique avoids the need to write complex cleanup code when allocating resources.

However, constructors do not offer the same protection. Because a constructor is involved in allocating resources, it does not automatically free any resources it allocates if it terminates prematurely. The C++ Standard, [except.ctor], paragraph 2 [ISO/IEC 14882-2014], states the following:

An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.

...

Resources must not be leaked as a result of throwing an exception, including during the construction of an object.

This rule is a subset of MEM51-CPP. Properly deallocate dynamically allocated resources, as all failures to deallocate resources violate that rule.

Noncompliant Code Example

In this noncompliant code example, pst is not properly released when process_item throws an exception, causing a resource leak:.

Code Block
bgColor#FFcccc
langcpp
#include <new>
 
struct SomeType {
  SomeType() noexcept; // Performs nontrivial initialization.
  ~SomeType(); // Performs nontrivial finalization.
  void process_item() noexcept(false);
};
 
void f() {
  SomeType *pst = new (std::nothrow) SomeType();
  if (!pst) {
    // Handle error
    return;
  }
 
  try {
    pst->process_item();
  } catch (...) {
    // HandleProcess error, but do not recover from it; rethrow.
    throw;
  }
  delete pst;
}

Compliant Solution (delete)

In this compliant solution, the exception handler frees pst by calling delete:.

Code Block
bgColor#ccccff
langcpp
#include <new>

struct SomeType {
  SomeType() noexcept; // Performs nontrivial initialization.
  ~SomeType(); // Performs nontrivial finalization.

  void process_item() noexcept(false);
};

void f() {
  SomeType *pst = new (std::nothrow) SomeType();
  if (!pst) {
    // Handle error
    return;
  }
  try {
    pst->process_item();
  } catch (...) {
    // HandleProcess error, but do not recover from it; rethrow.
    delete pst;
    throw;
  }
  delete pst;
}

This compliant solution complies with MEM51-CPP. Properly deallocate dynamically allocated resources. However, although handling resource cleanup in catch clauses works, it can While this compliant solution properly releases its resources using catch clauses, this approach can have some disadvantages:

  • Each distinct cleanup requires its own try and catch blocks.
  • The cleanup operation must not throw any exceptions.

...

Code Block
bgColor#ccccff
langcpp
struct SomeType {
  SomeType() noexcept; // Performs nontrivial initialization.
  ~SomeType(); // Performs nontrivial finalization.

  void process_item() noexcept(false);
};

void f() {
  SomeType st;
  try {
    st.process_item();
  } catch (...) {
    // HandleProcess error, but do not recover from it; rethrow.
    throw;
  } // After re-throwing the exception, the destructor is run for st.
} // If f() exits without throwing an exception, the destructor is run for st.

Noncompliant Code Example

...

This compliant solution mitigates the potential failures by releasing a and b if an exception is thrown during their allocation or during init():.

Code Block
bgColor#ccccff
langcpp
struct A {/* ... */};
struct B {/* ... */};

 
class C {
  A *a;
  B *b;
protected:
  void init() noexcept(false);
public:
  C() : a(nullptr), b(nullptr) {
    try {
      a = new A();
      b = new B();
      init();
    } catch (...) {
      delete a;
      delete b;
      throw;
    }
  }
};

...

This compliant solution uses std::unique_ptr to create objects that clean up after themselves should anything go wrong in the C::C() constructor (see MSC17-CPP. Do not use deprecated or obsolescent functionality for more information on . The std::unique_ptr).

...

hiddentrue

...

applies the principles of RAII to pointers.

Code Block
bgColor#ccccff
langcpp
#include <memory>
 
struct A {/* ... */};
struct B {/* ... */};

class C {
  std::unique_ptr<A> a;
  std::unique_ptr<B> b;
protected:
  void init() noexcept(false);
public:
  C() : a(new A()), b(new B()) {
    init();
  }
};

...

Memory and other resource leaks will eventually cause a program to crash. If an attacker can provoke repeated resource leaks by forcing an exception to be thrown through the submission of suitably crafted data, then the attacker can mount a denial-of-service attack.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR57-CPP

Low

Probable

High

P2

L3

Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

ALLOC.LEAK

Leak
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

DF4756, DF4757, DF4758


Klocwork
Include Page
Klocwork_V
Klocwork_V

CL.MLK
MLK.MIGHT
MLK.MUST
MLK.RET.MIGHT
MLK.RET.MUST
RH.LEAK


LDRA tool suite
Include Page
LDRA_V
LDRA_V

50 D

Partially implemented

Parasoft C/C++test
9.5BD-RES-LEAKS 
Include Page
Parasoft_V
Parasoft_V

CERT_CPP-ERR57-a

Ensure resources are freed

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: ERR57-CPP

Checks for:

  • Resource leak caused by exception
  • Object left in partially initialized state
  • Bad allocation in constructor

Related Vulnerabilities

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

Related Guidelines

Bibliography

[Cline 2009]

Question 17.2, I'm still not convinced: A 4-line code snippet shows that return-codes aren't any worse than exceptions;
why should I therefore use exceptions on an application that is orders of magnitude larger?

[ISO/IEC 14882-2014]Subclause 15.2, "Constructors and Destructors"
[Meyers
96
1996]Item 9, "Use Destructors to Prevent Resource Leaks"
[Stroustrup 2001]"Exception-Safe Implementation Techniques"

...


...

Image Modified Image Modified Image Modified