From 4dc5f7f75ca02391a1c246ee426022dfdae8c770 Mon Sep 17 00:00:00 2001 From: Weaselbot Date: Sun, 21 Jun 2026 20:43:44 -0400 Subject: [PATCH] Fix self-move-assignment and leak in ConflictSet move-assignment The user-declared move-assignment operator overwrote `impl` without first destroying the existing implementation object, leaking all memory and resources owned by the left-hand side. Self-move-assignment also set `impl` to nullptr, leaving the object invalid and leaking the old state. Fix all three implementations (ConflictSet.cpp, SkipList.cpp, HashTable.cpp) to guard against self-assignment and to destroy/free the old `impl` before taking ownership of `other.impl`. --- ConflictSet.cpp | 7 ++++++- HashTable.cpp | 8 +++++++- SkipList.cpp | 7 ++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 26d173d..bba8490 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -5589,7 +5589,12 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept : impl(std::exchange(other.impl, nullptr)) {} ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept { - impl = std::exchange(other.impl, nullptr); + if (this != &other) { + if (impl) { + internal_destroy(impl); + } + impl = std::exchange(other.impl, nullptr); + } return *this; } diff --git a/HashTable.cpp b/HashTable.cpp index e3fa477..f76e8c2 100644 --- a/HashTable.cpp +++ b/HashTable.cpp @@ -119,7 +119,13 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept : impl(std::exchange(other.impl, nullptr)) {} ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept { - impl = std::exchange(other.impl, nullptr); + if (this != &other) { + if (impl) { + impl->~Impl(); + safe_free(impl, sizeof(Impl)); + } + impl = std::exchange(other.impl, nullptr); + } return *this; } diff --git a/SkipList.cpp b/SkipList.cpp index fe09147..7cd7a1e 100644 --- a/SkipList.cpp +++ b/SkipList.cpp @@ -981,7 +981,12 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept : impl(std::exchange(other.impl, nullptr)) {} ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept { - impl = std::exchange(other.impl, nullptr); + if (this != &other) { + if (impl) { + internal_destroy(impl); + } + impl = std::exchange(other.impl, nullptr); + } return *this; }