HashTable: Assert on iteration attempt over table during clear/rehash

It doesn't seem sane to try to iterate over a HashTable while it's in
the middle of being cleared. Since this might cause strange problems,
this patch adds an assertion if an iterator is constructed during
clear() or rehash() of a HashTable.
This commit is contained in:
Andreas Kling 2019-07-31 10:12:45 +02:00
parent eccc3c3ef0
commit f10e850644

View file

@ -3,6 +3,7 @@
#include <AK/Assertions.h> #include <AK/Assertions.h>
#include <AK/SinglyLinkedList.h> #include <AK/SinglyLinkedList.h>
#include <AK/StdLibExtras.h> #include <AK/StdLibExtras.h>
#include <AK/TemporaryChange.h>
#include <AK/Traits.h> #include <AK/Traits.h>
#include <AK/kstdio.h> #include <AK/kstdio.h>
@ -59,6 +60,8 @@ private:
, m_is_end(is_end) , m_is_end(is_end)
, m_bucket_iterator(bucket_iterator) , m_bucket_iterator(bucket_iterator)
{ {
ASSERT(!table.m_clearing);
ASSERT(!table.m_rehashing);
if (!is_end && !m_table.is_empty() && !(m_bucket_iterator != BucketIteratorType::universal_end())) { if (!is_end && !m_table.is_empty() && !(m_bucket_iterator != BucketIteratorType::universal_end())) {
m_bucket_iterator = m_table.bucket(0).begin(); m_bucket_iterator = m_table.bucket(0).begin();
if (m_bucket_iterator.is_end()) if (m_bucket_iterator.is_end())
@ -146,7 +149,6 @@ public:
ConstIterator begin() const { return ConstIterator(*this, is_empty()); } ConstIterator begin() const { return ConstIterator(*this, is_empty()); }
ConstIterator end() const { return ConstIterator(*this, true); } ConstIterator end() const { return ConstIterator(*this, true); }
template<typename Finder> template<typename Finder>
Iterator find(unsigned hash, Finder finder) Iterator find(unsigned hash, Finder finder)
{ {
@ -221,6 +223,8 @@ private:
int m_size { 0 }; int m_size { 0 };
int m_capacity { 0 }; int m_capacity { 0 };
bool m_clearing { false };
bool m_rehashing { false };
}; };
template<typename T, typename TraitsForT> template<typename T, typename TraitsForT>
@ -268,6 +272,7 @@ void HashTable<T, TraitsForT>::set(const T& value)
template<typename T, typename TraitsForT> template<typename T, typename TraitsForT>
void HashTable<T, TraitsForT>::rehash(int new_capacity) void HashTable<T, TraitsForT>::rehash(int new_capacity)
{ {
TemporaryChange change(m_rehashing, true);
new_capacity *= 2; new_capacity *= 2;
auto* new_buckets = new Bucket[new_capacity]; auto* new_buckets = new Bucket[new_capacity];
auto* old_buckets = m_buckets; auto* old_buckets = m_buckets;
@ -287,6 +292,7 @@ void HashTable<T, TraitsForT>::rehash(int new_capacity)
template<typename T, typename TraitsForT> template<typename T, typename TraitsForT>
void HashTable<T, TraitsForT>::clear() void HashTable<T, TraitsForT>::clear()
{ {
TemporaryChange change(m_clearing, true);
if (m_buckets) { if (m_buckets) {
delete[] m_buckets; delete[] m_buckets;
m_buckets = nullptr; m_buckets = nullptr;