The memory leak vulnerability documented in ISO/IEC 24772-1:2024 clause 6.39 exists in C++, unless the programmer takes steps to avoid it. A leak occurs when an object whose lifetime (see 4.4) has not ended but there are no more variables, pointers or references to that object.
See ISO/IEC TR 24772-3 for the vulnerabilities associated with the C functions malloc()
, calloc()
, realloc()
and free()
.
C++ has an additional vulnerability in that it provides multiple alternatives for allocation and deallocation.
Failing to match the deallocation to the corresponding allocation results in undefined behaviour [EWF]. For example, if an array new[]
expression was used to allocate and create an array then array delete[]
must be used for its destruction and release to avoid undefined behaviour.
C++ destructors allow scope-based resource management (RAII) (Note: - put in Terms and definitions) which mitigates memory leaks by automatically calling the destructor when the lifetime of an object ends, thereby providing the opportunity to release their memory. The standard library provides container classes that follow the scope-based resource management idiom for the management of memory resources. Additionally, the standard library provides the class templates std::unique_ptr
and std::shared_ptr
for managing heap-allocated objects.
Ignoring issues with constructors throwing exceptions during heap allocation with a new
expression can cause leaks. Using smart pointers through the factory functions std::make_unique()
and std::make_shared()
assists in avoiding memory leaks.
If using functions that manage memory using the C library mechanisms is unavoidable, wrapping such a pointer immediately into a specialization of std::unique_ptr<>
that uses free()
in its deleter object ensures that memory is correctly released when the unique_ptr
is destroyed, for example:
struct free_deleter{
template <typename T>
void operator()(T *p) const {
std::free(const_cast<std::remove_const_t<T>*>(p));
}
};template <typename T>
using unique_C_ptr=std::unique_ptr<T,free_deleter>;
//...
// abi::__cxa_demangle() returns a pointer to be released with free()
inline auto plain_demangle(char const *name){
char const> result {abi::__cxa_demangle(name,0,0,0)};
unique_C_ptr<return result;
}
Modern C++ provides a class hierarchy, std::pmr::memory_resource
, that contains advanced allocation strategies and removes the need for explicit allocation/deallocation from the programmer, as shown below.
#include <array>
#include <cstdlib>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>
int main()
{using namespace std;
std::byte, 200'000> buf;
array<
pmr::monotonic_buffer_resource pool{buf.data(), buf.size()};
pmr::vector<pmr::string> v{&pool};for (int i=0; i != 1000; ++i)
"yet another longer string");
v.emplace_back( }
When using C++ allocators that are not derived from std::pmr::memory_resource
or are not part of an allocator provided by a library, care is needed to avoid vulnerabilities due to memory leaks due to issues in allocator code.
The library functions std::construct_at()
and std::destroy_at()
are simpler than and preferrable to placement new and destructor calls.
STOPPED HERE.
ISSUES WITH SHARED_PTR AND weak ptr or std::make_shared()
. Using std::shared_ptr()
can cause memory leaks if it is used to create a cyclic data structure that is not internally connected using weak pointers. Y_shr -> A -> B -> C -> A X_shr -> A shared_ptr differentiates between ownership and reference to A Shared_ptr
is a smart pointer that retains shared ownership f an object through a pointer. Shared_ptr can also own zero objects. A weak_ptr is a smart pointer that holds a non-owning reference to an object that is managed by shared_ptr. A weak_ptr must be converted to a shared_ptr in order to access the referenced object.
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Apply the avoidance mechanism of ISO/IEC 24772-1:2024 6.39.5
Refrain from using the C functions malloc()
, calloc()
, realloc()
and free()
wherever possible.
Avoid mixing C-based functions and C++ memory management functions.
Prefer PMR
Prefer containers like those in the standard library over any other form of memory management.
Use smart pointers and their factory functions to allocate and manage heap memory.
For heap fragmentation issues, use special memory resource objects with appropriate allocation strategies.
If using std::shared_ptr
in potentially cyclic data structures, break cycles using std::weak_ptr
.
Use static analysis to prevent uses of C-library memory management functions and direct calls to operators new
and delete
.
Use dynamic analysis to detect memory leaks and issues with heap fragmentation.