Versions Compared

Key

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

It is important that resources are reclaimed when exceptions are thrown. Throwing an An exception being thrown may result in cleanup code being bypassed. As a result, it is the responsibility of the exception handler to properly clean up. This may be problematic if the exception is to be caught in a different function or module. Instead, it is preferable if resources are reclaimed automatically when objects go out of scope.

Non-Compliant Code Example

, or an object being left in a partially-initialized state. It is preferable if resources are reclaimed automatically when objects go out of scope by using the RAII design pattern [Stroustrup 2001]. This saves you from having to worry about complex cleanup code when allocating resources.

However, constructors do not offer the same protection. Since 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 states [ISO/IEC 14882-2014]:

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.

It is generally recommended that constructors that cannot complete their job should throw exceptions, rather than exit normally, leaving their object in a 'half-baked' state [Cline 2009].

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

Noncompliant Code Example

In this noncompliant code example, pst is not properly released when processItem throws an exception, causing a resource leak:In this non-compliant code example, the resources associated with the object pointed to by pst are not recovered in the event that processItem throws an exception, thereby potentially causing a resource leak.

Code Block
bgColor#FFcccc
langcpp
while (moreToDo#include <new>
 
struct SomeType {
  void processItem() noexcept(false);
};
 
void f() {
  SomeType *pst = new (std::nothrow) SomeType();
  if (!pst) {
    // Handle error
    return;
  }
 
  try {
    pst->processItem();
  }
  catch (...) {
    // dealHandle with exceptionerror
    throw;
  }
  delete pst;
}

Compliant Solution (delete)

In this codecompliant solution, the exception handler recovers the resources associated with the object pointed to by pst.frees pst by calling delete:

Code Block
bgColor#ccccff
langcpp
while (moreToDo#include <new>

struct SomeType {
  void processItem() noexcept(false);
};

void f() {
  SomeType *pst = new (std::nothrow) SomeType();
  if (!pst) {
    // Handle error
    return;
  }
  try {
    pst->processItem();
  }
  catch (...) {
    // dealHandle with exceptionerror
    delete pst;
    throw;
  }
  delete pst;
}

Handling This compliant solution complies with VOID MEM31-CPP. Free dynamically allocated memory exactly once, however, while handling resource cleanup in catch clauses does work, but it can have several disadvantages:

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

Compliant Solution (RAII Design Pattern)

A better approach would be to employ RAII. This forces every object to 'clean up after itself' in the face of abnormal behavior, preventing the programmer from having to do so. A judicious unique_ptr would free the resource whether an error occurs or notThis approach additionally benefits by not requiring statements to handle resource allocation errors in conformance with MEM32-CPP. Detect and handle memory allocation errors.

Code Block
bgColor#ccccff
langcpp
struct SomeType {
  void processItem() noexcept(false);
};

void f() {
  SomeType st;
  try {
    st.processItem();
  } catch (...) {
    // Handle error
    throw;
  }
}

Noncompliant Code Example

In this noncompliant code example, the C::C() constructor might fail to allocate memory for a, might fail to allocate memory for b, or might throw an exception in the init() method. If init() throws an exception, then neither a nor b will be released. Likewise, if the allocation for b fails, then a will not be released.

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

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

Compliant Solution (try/catch)

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
#include <new>
 
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();
    }while (moreToDo) {
  std::unique_ptr<SomeType> pst = new SomeType();
  try {
    pst->processItem();
  }
  catch (...) {
       // deal with exception
delete a;
      delete b;
      throw;
    }
  }
};

Compliant Solution (std::unique_ptr)

This compliant solution utilizies std::unique_ptr to create objects that clean up after themselves should anything go wrong in the C::C() constructor. See MEM00-CPP. Don't use auto_ptr where copy semantics might be expected for more information on std::unique_ptr.

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();
  }
}; // pst automatically freed
  }
  // pst automatically freed
}

Risk Assessment

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

MEM44-CPP

lowLow

probableProbable

highHigh

P2

L3

Automated Detection

Tool

Version

Checker

Description

 

  

 

Related Vulnerabilities

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

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]15.2, "Constructors and Destructors"
[Meyers 96]Item 9: "Use destructors to prevent resource leaks".
[Stroustrup 2001]"Exception-Safe Implementation Techniques"
[Cline 2009]

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?"

...

Image Modified Image Modified Image Modified