Skip to content

Memory leak in overlapping relocation test functions #7184

@GitMasterJatin

Description

@GitMasterJatin

The setup<T>() helper allocates two buffers (mem1, mem2) and returns them as std::pair<T*, T*>.

In non-overlapping tests, both buffers are correctly freed:

auto [ptr1, ptr2] = setup<trivially_relocatable_struct>();
// ... test ...
std::free(ptr1);
std::free(ptr2);  // ✓ both freed

However, in overlapping tests, the second buffer is captured but never freed:

auto [ptr, ___] = setup<trivially_relocatable_struct_overlapping>();
// ... test uses only ptr ...
std::free(ptr);  // mem2 is leaked

Since overlapping tests only use a single buffer (in-place relocation), the second allocation is unnecessary and gets leaked every time.

Impact
~20 leak sites across multiple relocation test files
Each leak allocates N * sizeof(T) (N = 500)
Repeats across test runs, leading to unnecessary memory usage
Root Cause

setup<T>() was designed for non-overlapping tests that require two buffers.
Overlapping tests reuse a single buffer but still call the same helper, which allocates a second buffer that is never used or freed.

The placeholder binding (___) makes it clear the second value is intentionally ignored, but the allocation still happens.

Affected Areas
uninitialized_relocate.cpp
uninitialized_relocaten.cpp
uninitialized_relocate_backward.cpp
uninitialized_relocate_sender.cpp
uninitialized_relocaten_sender.cpp
uninitialized_relocate_backward_sender.cpp

(affecting test_overlapping() and test_right_overlapping() blocks)

Proposed Fix
Option A — Free the unused buffer (quick fix)
auto [ptr, ptr2_unused] = setup<trivially_relocatable_struct_overlapping>();
// ... test ...
std::free(ptr);
std::free(ptr2_unused);
Option B — Introduce a single-buffer helper (preferred)
template <typename T>
T* setup_single()
{
    clear();
    void* mem = std::malloc(N * sizeof(T));
    HPX_TEST(mem);

    T* ptr = static_cast<T*>(mem);
    for (int i = 0; i < N; i++)
        hpx::construct_at(ptr + i, i);

    HPX_TEST(T::made.size() == N);
    return ptr;
}

Then update overlapping tests to use:

auto ptr = setup_single<trivially_relocatable_struct_overlapping>();
// ... test ...
std::free(ptr);

This avoids unnecessary allocation, makes ownership explicit, and eliminates the risk of leaks.

Happy to submit a PR if this approach looks good 


Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions