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 | ||||
|---|---|---|---|---|
| ||||
#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 (...) {
// Process error, but do not recover from it; rethrow.
throw;
}
delete pst;
}
|
...
In this compliant solution, the exception handler frees pst by calling delete:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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 (...) {
// Process error, but do not recover from it; rethrow.
delete pst;
throw;
}
delete pst;
} |
...
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 | ||||
|---|---|---|---|---|
| ||||
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;
}
}
};
|
...
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 |
| ALLOC.LEAK | Leak | ||||||
| Helix QAC |
| DF4756, DF4757, DF4758 | |||||||
| Klocwork |
| CL.MLK | |||||||
| LDRA tool suite |
| 50 D | Partially implemented | ||||||
| Parasoft C/C++test |
| CERT_CPP-ERR57-a | Ensure resources are freed | |||||||
| Polyspace Bug Finder |
| CERT C++: ERR57-CPP | Checks for:
|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
| SEI CERT C++ Coding Standard | MEM51-CPP. Properly deallocate dynamically allocated resources |
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; |
| [ISO/IEC 14882-2014] | Subclause 15.2, "Constructors and Destructors" |
| [Meyers |
| 1996] | Item 9, "Use Destructors to Prevent Resource Leaks" |
| [Stroustrup 2001] | "Exception-Safe Implementation Techniques" |
...
...