
...
Do not call a deallocation function on anything other than nullptr
, or a pointer returned by the corresponding allocation function described by the following.
Allocator | Deallocator |
---|---|
global operator new()/new | global operator delete ()/delete |
global operator new[]()/new[] | global operator delete[]()/delete[] |
class-specific operator new()/new | class-specific operator delete ()/delete |
class-specific operator new[]()/new[] | class-specific operator delete[]()/delete[] |
placement operator new () | N/A |
allocator<T>::allocate() |
|
std::malloc() , std::calloc() , std::realloc() | std::free() |
std::get_temporary_buffer() | std::return_temporary_buffer() |
Page properties | ||
---|---|---|
| ||
While the wording for |
...
In this noncompliant code example, the local variable s1
space
is passed as the expression to the placement new
operator. The resulting pointer of that call is then passed to ::operator delete()
, resulting in undefined behavior due to ::operator delete()
attempting to free memory that was not returned by ::operator new()
.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> struct S { S() { std::cout << "S::S()" << std::endl; } ~S() { std::cout << "S::~S()" << std::endl; } }; void f() { alignas(struct S s1) char space[sizeof(struct S)]; S *s2s1 = new (&s1space) S; // ... delete s2s1; } |
Compliant Solution (placement new()
)
This compliant solution removes the call to ::operator delete()
, allowing s1
to be destroyed as a result of its normal object lifetime terminationinstead explicitly calling s1
's destructor. This is one of the few times when explicitly invoking a destructor is warranted.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> struct S { S() { std::cout << "S::S()" << std::endl; } ~S() { std::cout << "S::~S()" << std::endl; } }; void f() { alignas(struct S) s1; S *s2char space[sizeof(struct S)]; S *s1 = new (&s1space) S; // ... s1->~S(); } |
Noncompliant Code Example (Uninitialized delete
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
void f() { int *array = new int[10]; // ... delete array; } |
Compliant Solution (array new[]
)
In the compliant solution, the code is fixed by replacing the call to delete
with a call to delete []
to adhere to the correct pairing of memory allocation and deallocation functions.
Code Block | ||||
---|---|---|---|---|
| ||||
void f() { int *array = new int[10]; // ... delete[] array; } |
...
Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in undefined behavior, which can lead to exploitable vulnerabilities.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM51-CPP | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description |
---|
Astrée |
|
|
|
clang-analyzer-cplusplus.NewDeleteLeaks
-Wmismatched-new-delete
clang-analyzer-unix.MismatchedDeallocator
invalid_dynamic_memory_allocation dangling_pointer_use | |||||||||
Axivion Bauhaus Suite |
| CertC++-MEM51 | |||||||
Clang |
| clang-analyzer-cplusplus.NewDeleteLeaks -Wmismatched-new-delete | Checked |
by clang-tidy , but does not catch all violations of this rule | ||||||||
CodeSonar |
| ALLOC. |
DF |
ALLOC.LEAK | Double free Type mismatch |
Leak | ||
Helix QAC |
|
|
|
232 S, 236 S, 239 S, 407 S, 469 S, 470 S, 483 S, 484 S, 485 S, 64 S, 112 D
Partially implemented
C++2110, C++2111, C++2112, C++2113, C++2118, C++3337, C++3339, C++4262, C++4263, C++4264 | |||||||||
Klocwork |
| CL.FFM.ASSIGN CL.FFM.COPY CL.FMM CL.SHALLOW.ASSIGN CL.SHALLOW.COPY FMM.MIGHT FMM.MUST FNH.MIGHT FNH.MUST FUM.GEN.MIGHT FUM.GEN.MUST UNINIT.CTOR.MIGHT UNINIT.CTOR.MUST UNINIT.HEAP.MIGHT UNINIT.HEAP.MUST | |||||||
LDRA tool suite |
| 232 S, 236 S, 239 S, 407 S, 469 S, 470 S, 483 S, 484 S, 485 S, 64 D, 112 D | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_CPP-MEM51-a | Use the same form in corresponding calls to new/malloc and delete/free | ||||||
Parasoft Insure++ | Runtime detection | ||||||||
Polyspace Bug Finder |
| CERT C++: MEM51-CPP | Checks for:
Rule partially covered. | ||||||
PVS-Studio |
| V515, V554, V611, V701, V748, V773, V1066 | |||||||
SonarQube C/C++ Plugin |
| S1232 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime |
SEI CERT C Coding Standard | MEM31-C. Free dynamically allocated memory when no longer needed |
MITRE CWE | CWE 590, Free of Memory Not on the Heap |
Bibliography
[Dowd 2007] | "Attacking delete and delete [] in C++" | ||
[Henricson 1997] | Rule 8.1, "delete should only be used with new" Rule 8.2, " delete [] should only be used with new []" | ||
[ISO/IEC 14882-2014] | Subclause 5.3.5, "Delete" | ||
[Meyers 2005] | Item 16, "Use the Same Form in Corresponding Uses of new and delete " | ||
[Seacord 2013] | Chapter 4, "Dynamic Memory Management" | ||
[Viega 2005] | "Doubly Freeing Memory" |
...
...