mirror of
https://github.com/ETLCPP/etl.git
synced 2026-07-30 16:26:17 +08:00
Fix etl::histogram copy/move not preserving start_index (#1485)
The run-time-offset specialization of etl::histogram stores a start_index member used to map keys to bins (accumulator[key - start_index]). Its copy constructor, move constructor, copy assignment, and move assignment copied only the accumulator and left start_index uninitialized, so a copied or moved histogram indexed the wrong bin in operator[]/add(), causing out-of-bounds access (undefined behavior). All four special member functions now also copy start_index. The compile-time-offset specialization is unaffected, as its start index is a template constant rather than a data member. Add regression tests covering copy/move construction and assignment. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
5cd2f28cd5
commit
98cb365d4c
@ -296,6 +296,7 @@ namespace etl
|
|||||||
histogram(const histogram& other)
|
histogram(const histogram& other)
|
||||||
{
|
{
|
||||||
this->accumulator = other.accumulator;
|
this->accumulator = other.accumulator;
|
||||||
|
start_index = other.start_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ETL_USING_CPP11
|
#if ETL_USING_CPP11
|
||||||
@ -305,6 +306,7 @@ namespace etl
|
|||||||
histogram(histogram&& other)
|
histogram(histogram&& other)
|
||||||
{
|
{
|
||||||
this->accumulator = etl::move(other.accumulator);
|
this->accumulator = etl::move(other.accumulator);
|
||||||
|
start_index = other.start_index;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -314,6 +316,7 @@ namespace etl
|
|||||||
histogram& operator=(const histogram& rhs)
|
histogram& operator=(const histogram& rhs)
|
||||||
{
|
{
|
||||||
this->accumulator = rhs.accumulator;
|
this->accumulator = rhs.accumulator;
|
||||||
|
start_index = rhs.start_index;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -325,6 +328,7 @@ namespace etl
|
|||||||
histogram& operator=(histogram&& rhs)
|
histogram& operator=(histogram&& rhs)
|
||||||
{
|
{
|
||||||
this->accumulator = etl::move(rhs.accumulator);
|
this->accumulator = etl::move(rhs.accumulator);
|
||||||
|
start_index = rhs.start_index;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -248,6 +248,68 @@ namespace
|
|||||||
CHECK_EQUAL(0U, histogram2.count());
|
CHECK_EQUAL(0U, histogram2.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
// operator[] of the run time offset histogram uses the stored start index,
|
||||||
|
// so copying/moving must preserve it. Regression test: the copy/move
|
||||||
|
// constructors and assignment operators used to forget to copy start_index.
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_int_runtime_offset_copy_constructor_preserves_start_index)
|
||||||
|
{
|
||||||
|
IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end());
|
||||||
|
|
||||||
|
IntRuntimeOffsetHistogram histogram2(histogram1);
|
||||||
|
|
||||||
|
for (int key = Start; key < Start + static_cast<int>(Size); ++key)
|
||||||
|
{
|
||||||
|
CHECK_EQUAL(static_cast<int>(histogram1[key]), static_cast<int>(histogram2[key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_int_runtime_offset_copy_assignment_preserves_start_index)
|
||||||
|
{
|
||||||
|
IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end());
|
||||||
|
|
||||||
|
IntRuntimeOffsetHistogram histogram2(Start);
|
||||||
|
histogram2 = histogram1;
|
||||||
|
|
||||||
|
for (int key = Start; key < Start + static_cast<int>(Size); ++key)
|
||||||
|
{
|
||||||
|
CHECK_EQUAL(static_cast<int>(histogram1[key]), static_cast<int>(histogram2[key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ETL_USING_CPP11
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_int_runtime_offset_move_constructor_preserves_start_index)
|
||||||
|
{
|
||||||
|
IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end());
|
||||||
|
IntRuntimeOffsetHistogram histogram_source(Start, input2.begin(), input2.end());
|
||||||
|
|
||||||
|
IntRuntimeOffsetHistogram histogram2(etl::move(histogram_source));
|
||||||
|
|
||||||
|
for (int key = Start; key < Start + static_cast<int>(Size); ++key)
|
||||||
|
{
|
||||||
|
CHECK_EQUAL(static_cast<int>(histogram1[key]), static_cast<int>(histogram2[key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
TEST(test_int_runtime_offset_move_assignment_preserves_start_index)
|
||||||
|
{
|
||||||
|
IntRuntimeOffsetHistogram histogram1(Start, input2.begin(), input2.end());
|
||||||
|
IntRuntimeOffsetHistogram histogram_source(Start, input2.begin(), input2.end());
|
||||||
|
|
||||||
|
IntRuntimeOffsetHistogram histogram2(Start);
|
||||||
|
histogram2 = etl::move(histogram_source);
|
||||||
|
|
||||||
|
for (int key = Start; key < Start + static_cast<int>(Size); ++key)
|
||||||
|
{
|
||||||
|
CHECK_EQUAL(static_cast<int>(histogram1[key]), static_cast<int>(histogram2[key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
TEST(test_string_histogram_constructor)
|
TEST(test_string_histogram_constructor)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user