Skip to content

Commit 379e875

Browse files
authored
Merge pull request #1482 from LLNL/bugfix/yang39/mem-leak
Fix a memory leak in axom::Array copy constructor
2 parents 630ae9e + c9101fe commit 379e875

File tree

3 files changed

+31
-78
lines changed

3 files changed

+31
-78
lines changed

RELEASE-NOTES.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ to use Open CASCADE's file I/O capabilities in support of Quest applications.
4343
- Fixes compilation issue with [email protected] on 32-bit Windows configurations.
4444
This required a [RAJA fix to avoid 64-bit intrinsics](https://github.com/LLNL/RAJA/pull/1746),
4545
as well as support for 32-bit `Word`s in Slam's `BitSet` class.
46+
- Fixes a memory leak in `axom::Array` copy constructor.
4647

4748
## [Version 0.10.1] - Release date 2024-10-22
4849

src/axom/core/Array.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,8 @@ AXOM_HOST_DEVICE Array<T, DIM, SPACE>::Array(const Array& other)
11391139
assert(false);
11401140
#endif
11411141
#else
1142-
initialize(other.size(), other.capacity());
1142+
this->setCapacity(other.capacity());
1143+
m_executeOnGPU = axom::isDeviceAllocator(m_allocator_id);
11431144
// Use fill_range to ensure that copy constructors are invoked for each
11441145
// element.
11451146
MemorySpace srcSpace = SPACE;
@@ -1149,9 +1150,10 @@ AXOM_HOST_DEVICE Array<T, DIM, SPACE>::Array(const Array& other)
11491150
}
11501151
OpHelper {m_allocator_id, m_executeOnGPU}.fill_range(m_data,
11511152
0,
1152-
m_num_elements,
1153+
other.size(),
11531154
other.data(),
11541155
srcSpace);
1156+
this->updateNumElements(other.size());
11551157
#endif
11561158
}
11571159

src/axom/core/tests/core_array.hpp

+26-76
Original file line numberDiff line numberDiff line change
@@ -2389,102 +2389,52 @@ TEST(core_array, reserve_nontrivial_reloc_um)
23892389
}
23902390
#endif
23912391

2392-
// Regression test for a memory leak in axom::Array's copy/move/initialization
2393-
template <typename T1, typename T2>
2394-
auto make_arr_data(int SZ1, int SZ2)
2395-
-> std::pair<axom::Array<axom::Array<T1>>, axom::Array<axom::Array<T2>>>
2392+
class AllocatingDefaultInit
23962393
{
2397-
using Arr1 = axom::Array<axom::Array<T1>>;
2398-
using Arr2 = axom::Array<axom::Array<T2>>;
2394+
public:
2395+
AllocatingDefaultInit() { m_value.resize(32); }
23992396

2400-
T1 val1 {};
2401-
T2 val2 {};
2402-
2403-
Arr1 arr1(SZ1, 2 * SZ1);
2404-
for(int i = 0; i < SZ1; ++i)
2405-
{
2406-
arr1[i].resize(i + 10);
2407-
arr1[i].shrink();
2408-
arr1[i].push_back(val1);
2409-
}
2410-
2411-
Arr2 arr2(SZ2, 2 * SZ2);
2412-
for(int i = 0; i < SZ2; ++i)
2413-
{
2414-
arr2[i].resize(i + 10);
2415-
arr2[i].shrink();
2416-
arr2[i].push_back(val2);
2417-
}
2418-
arr2.shrink();
2419-
2420-
return {std::move(arr1), std::move(arr2)};
2421-
}
2397+
private:
2398+
axom::Array<int> m_value;
2399+
};
24222400

2423-
TEST(core_array, regression_array_move)
2401+
TEST(core_array, array_ctors_leak)
24242402
{
2425-
using T1 = int;
2426-
using Arr1 = axom::Array<axom::Array<T1>>;
2427-
2428-
using T2 = NonTriviallyRelocatable;
2429-
using Arr2 = axom::Array<axom::Array<T2>>;
2430-
2431-
using PArrArr = std::pair<Arr1, Arr2>;
2403+
using Array = axom::Array<AllocatingDefaultInit>;
24322404

2405+
// Initialize test array
24332406
constexpr int SZ1 = 20;
2434-
constexpr int SZ2 = 30;
2407+
Array data(SZ1);
24352408

2409+
// axom::Array copy constructor
24362410
{
2437-
PArrArr pr;
2438-
pr = make_arr_data<T1, T2>(SZ1, SZ2);
2411+
Array arr_copy {data};
24392412

2440-
EXPECT_EQ(SZ1, pr.first.size());
2441-
EXPECT_EQ(2 * SZ1, pr.first.capacity());
2442-
2443-
EXPECT_EQ(SZ2, pr.second.size());
2444-
EXPECT_EQ(SZ2, pr.second.capacity());
2413+
EXPECT_EQ(SZ1, arr_copy.size());
24452414
}
24462415

2416+
// axom::Array copy assignment operator
24472417
{
2448-
auto pr = make_arr_data<T1, T2>(SZ1, SZ2);
2449-
2450-
EXPECT_EQ(SZ1, pr.first.size());
2451-
EXPECT_EQ(2 * SZ1, pr.first.capacity());
2418+
Array arr_copy {SZ1 + 10};
2419+
arr_copy = data;
24522420

2453-
EXPECT_EQ(SZ2, pr.second.size());
2454-
EXPECT_EQ(SZ2, pr.second.capacity());
2421+
EXPECT_EQ(SZ1, arr_copy.size());
24552422
}
24562423

2424+
// axom::Array move constructor
24572425
{
2458-
auto pr = make_arr_data<T1, T2>(SZ1, SZ2);
2459-
EXPECT_EQ(SZ1, pr.first.size());
2460-
EXPECT_EQ(2 * SZ1, pr.first.capacity());
2461-
EXPECT_EQ(SZ2, pr.second.size());
2462-
EXPECT_EQ(SZ2, pr.second.capacity());
2426+
Array tmp_move_from {data};
2427+
Array arr_move {std::move(tmp_move_from)};
24632428

2464-
pr = make_arr_data<T1, T2>(SZ2, SZ1);
2465-
EXPECT_EQ(SZ2, pr.first.size());
2466-
EXPECT_EQ(2 * SZ2, pr.first.capacity());
2467-
EXPECT_EQ(SZ1, pr.second.size());
2468-
EXPECT_EQ(SZ1, pr.second.capacity());
2429+
EXPECT_EQ(SZ1, arr_move.size());
24692430
}
24702431

2471-
// lots of copy and move assignments and constructions
2432+
// axom::Array move assignment operator
24722433
{
2473-
auto pr = make_arr_data<T1, T2>(SZ1, SZ2);
2474-
pr = make_arr_data<T1, T2>(5, 7);
2475-
2476-
auto pr2 = std::move(pr);
2477-
auto pr3 = pr2;
2478-
2479-
pr2 = make_arr_data<T1, T2>(13, 17);
2480-
2481-
auto pr4 {make_arr_data<T1, T2>(33, 44)};
2482-
2483-
auto pr5(std::move(pr4));
2434+
Array tmp_move_from {data};
2435+
Array arr_move {SZ1 + 10};
2436+
arr_move = std::move(tmp_move_from);
24842437

2485-
EXPECT_EQ(33, pr5.first.size());
2486-
EXPECT_EQ(66, pr5.first.capacity());
2487-
EXPECT_EQ(44, pr5.second.size());
2488-
EXPECT_EQ(44, pr5.second.capacity());
2438+
EXPECT_EQ(SZ1, arr_move.size());
24892439
}
24902440
}

0 commit comments

Comments
 (0)