Commit 42bce29f authored by Harris Hancock's avatar Harris Hancock

Implement InsertionOrderIndex move constructor/assignment operator

InsertionOrderIndex manages memory, but it didn't have an explicit move constructor or move assignment operator, causing segmentation faults and double frees.
parent 0ac813d9
...@@ -1101,6 +1101,66 @@ KJ_TEST("insertion order index") { ...@@ -1101,6 +1101,66 @@ KJ_TEST("insertion order index") {
} }
} }
KJ_TEST("insertion order index is movable") {
using UintTable = Table<uint, InsertionOrderIndex>;
kj::Maybe<UintTable> myTable;
{
UintTable yourTable;
yourTable.insert(12);
yourTable.insert(34);
yourTable.insert(56);
yourTable.insert(78);
yourTable.insert(111);
yourTable.insert(222);
yourTable.insert(333);
yourTable.insert(444);
yourTable.insert(555);
yourTable.insert(666);
yourTable.insert(777);
yourTable.insert(888);
yourTable.insert(999);
myTable = kj::mv(yourTable);
}
auto& table = KJ_ASSERT_NONNULL(myTable);
// At one time the following induced a segfault/double-free, due to incorrect memory management in
// InsertionOrderIndex's move ctor and dtor.
auto range = table.ordered();
auto iter = range.begin();
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 12);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 34);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 56);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 78);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 111);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 222);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 333);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 444);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 555);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 666);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 777);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 888);
KJ_ASSERT(iter != range.end());
KJ_EXPECT(*iter++ == 999);
KJ_EXPECT(iter == range.end());
}
} // namespace } // namespace
} // namespace _ } // namespace _
} // namespace kj } // namespace kj
...@@ -808,6 +808,19 @@ void BTreeImpl::Parent::eraseAfter(uint i) { ...@@ -808,6 +808,19 @@ void BTreeImpl::Parent::eraseAfter(uint i) {
const InsertionOrderIndex::Link InsertionOrderIndex::EMPTY_LINK = { 0, 0 }; const InsertionOrderIndex::Link InsertionOrderIndex::EMPTY_LINK = { 0, 0 };
InsertionOrderIndex::InsertionOrderIndex(): capacity(0), links(const_cast<Link*>(&EMPTY_LINK)) {} InsertionOrderIndex::InsertionOrderIndex(): capacity(0), links(const_cast<Link*>(&EMPTY_LINK)) {}
InsertionOrderIndex::InsertionOrderIndex(InsertionOrderIndex&& other)
: capacity(other.capacity), links(other.links) {
other.capacity = 0;
other.links = const_cast<Link*>(&EMPTY_LINK);
}
InsertionOrderIndex& InsertionOrderIndex::operator=(InsertionOrderIndex&& other) {
KJ_DASSERT(&other != this);
capacity = other.capacity;
links = other.links;
other.capacity = 0;
other.links = const_cast<Link*>(&EMPTY_LINK);
return *this;
}
InsertionOrderIndex::~InsertionOrderIndex() noexcept(false) { InsertionOrderIndex::~InsertionOrderIndex() noexcept(false) {
if (links != &EMPTY_LINK) delete[] links; if (links != &EMPTY_LINK) delete[] links;
} }
......
...@@ -1538,6 +1538,10 @@ class InsertionOrderIndex { ...@@ -1538,6 +1538,10 @@ class InsertionOrderIndex {
struct Link; struct Link;
public: public:
InsertionOrderIndex(); InsertionOrderIndex();
InsertionOrderIndex(const InsertionOrderIndex&) = delete;
InsertionOrderIndex& operator=(const InsertionOrderIndex&) = delete;
InsertionOrderIndex(InsertionOrderIndex&& other);
InsertionOrderIndex& operator=(InsertionOrderIndex&& other);
~InsertionOrderIndex() noexcept(false); ~InsertionOrderIndex() noexcept(false);
class Iterator { class Iterator {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment