Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: third_party/WebKit/Source/wtf/HashTable.h

Issue 1892533003: Catch illegal hash table modifications when they happen. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add reqd copy ctor Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/wtf/LinkedHashSet.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/wtf/HashTable.h
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h
index a1b96bc013b4352635951b34ab8a47f4d793831e..d43dc6cb63e1d316023172dbc294dc3f822c30fd 100644
--- a/third_party/WebKit/Source/wtf/HashTable.h
+++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -103,6 +103,29 @@ class LinkedHashSet;
template <WeakHandlingFlag x, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
struct WeakProcessingHashTableHelper;
+#if ENABLE(ASSERT)
+// HashTable and collections that build on it do not support modifications
+// while there is an iterator or HashTableAddResult on the stack.
+// The exception is ListHashSet, which has its own iterators that tolerate modification
+// of the underlying set.
+//
+// Constraint enforced by this scope object.
+template <typename HashTableType>
+class HashTableModificationForbiddenScope {
+public:
+ HashTableModificationForbiddenScope();
+ explicit HashTableModificationForbiddenScope(const HashTableType*);
+ HashTableModificationForbiddenScope(const HashTableModificationForbiddenScope&);
+
+ ~HashTableModificationForbiddenScope();
+
+ void leaveScope();
+
+private:
+ HashTableType* m_container;
+};
+#endif
+
typedef enum { HashItemKnownGood } HashItemKnownGoodTag;
template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
@@ -129,8 +152,7 @@ private:
: m_position(position)
, m_endPosition(endPosition)
#if ENABLE(ASSERT)
- , m_container(container)
- , m_containerModifications(container->modifications())
+ , m_modificationForbiddenScope(position != endPosition ? container : nullptr)
#endif
{
skipEmptyBuckets();
@@ -140,21 +162,9 @@ private:
: m_position(position)
, m_endPosition(endPosition)
#if ENABLE(ASSERT)
- , m_container(container)
- , m_containerModifications(container->modifications())
+ , m_modificationForbiddenScope(position != endPosition ? container : nullptr)
#endif
{
- ASSERT(m_containerModifications == m_container->modifications());
- }
-
- void checkModifications() const
- {
- // HashTable and collections that build on it do not support
- // modifications while there is an iterator in use. The exception is
- // ListHashSet, which has its own iterators that tolerate modification
- // of the underlying set.
- ASSERT(m_containerModifications == m_container->modifications());
- ASSERT(!m_container->accessForbidden());
}
public:
@@ -162,7 +172,6 @@ public:
GetType get() const
{
- checkModifications();
return m_position;
}
typename Traits::IteratorConstReferenceType operator*() const { return Traits::getToReferenceConstConversion(get()); }
@@ -171,9 +180,15 @@ public:
const_iterator& operator++()
{
ASSERT(m_position != m_endPosition);
- checkModifications();
++m_position;
skipEmptyBuckets();
+#if ENABLE(ASSERT)
+ // If now at the end, leave the forbidden scope. Waiting until
+ // the iterator goes out of (stack) scope disallows perfectly valid
+ // code idioms.
+ if (m_position == m_endPosition)
+ m_modificationForbiddenScope.leaveScope();
+#endif
return *this;
}
@@ -201,8 +216,7 @@ private:
PointerType m_position;
PointerType m_endPosition;
#if ENABLE(ASSERT)
- const HashTableType* m_container;
- int64_t m_containerModifications;
+ HashTableModificationForbiddenScope<HashTableType> m_modificationForbiddenScope;
#endif
};
@@ -277,14 +291,14 @@ public:
template <typename T, typename U, typename V> static void translate(T& location, U&&, V&& value) { location = std::forward<V>(value); }
};
-template <typename HashTableType, typename ValueType> struct HashTableAddResult final {
+template <typename HashTableType, typename ValueType>
+struct HashTableAddResult final {
STACK_ALLOCATED();
HashTableAddResult(const HashTableType* container, ValueType* storedValue, bool isNewEntry)
: storedValue(storedValue)
, isNewEntry(isNewEntry)
#if ENABLE(SECURITY_ASSERT)
- , m_container(container)
- , m_containerModifications(container->modifications())
+ , m_modificationForbiddenScope(container)
#endif
{
ALLOW_UNUSED_LOCAL(container);
@@ -298,18 +312,12 @@ template <typename HashTableType, typename ValueType> struct HashTableAddResult
~HashTableAddResult()
{
// If rehash happened before accessing storedValue, it's
- // use-after-free. Any modification may cause a rehash, so we check for
- // modifications here.
-
- // Rehash after accessing storedValue is harmless but will assert if the
- // AddResult destructor takes place after a modification. You may need
- // to limit the scope of the AddResult.
- ASSERT_WITH_SECURITY_IMPLICATION(m_containerModifications == m_container->modifications());
+ // use-after-free. Any modification may cause a rehash, so we enter
+ // a modification forbidden scope for the lifetime of this value.
}
private:
- const HashTableType* m_container;
- const int64_t m_containerModifications;
+ HashTableModificationForbiddenScope<HashTableType> m_modificationForbiddenScope;
#endif
};
@@ -413,14 +421,7 @@ public:
ASSERT(!Allocator::isGarbageCollected);
if (LIKELY(!m_table))
return;
- ASSERT(!m_accessForbidden);
-#if ENABLE(ASSERT)
- m_accessForbidden = true;
-#endif
deleteAllBucketsAndDeallocate(m_table, m_tableSize);
-#if ENABLE(ASSERT)
- m_accessForbidden = false;
-#endif
m_table = nullptr;
}
@@ -441,17 +442,14 @@ public:
unsigned size() const
{
- ASSERT(!m_accessForbidden);
return m_keyCount;
}
unsigned capacity() const
{
- ASSERT(!m_accessForbidden);
return m_tableSize;
}
bool isEmpty() const
{
- ASSERT(!m_accessForbidden);
return !m_keyCount;
}
@@ -493,17 +491,19 @@ public:
template <typename VisitorDispatcher> void trace(VisitorDispatcher);
#if ENABLE(ASSERT)
- bool accessForbidden() const { return m_accessForbidden; }
- int64_t modifications() const { return m_modifications; }
- void registerModification() { m_modifications++; }
- // HashTable and collections that build on it do not support modifications
- // while there is an iterator in use. The exception is ListHashSet, which
- // has its own iterators that tolerate modification of the underlying set.
- void checkModifications(int64_t mods) const { ASSERT(mods == m_modifications); }
+ void enterModificationForbiddenScope() { m_modificationForbidden++; }
+ void leaveModificationForbiddenScope()
+ {
+ ASSERT(m_modificationForbidden > 0);
+ m_modificationForbidden--;
+ }
+
+ void registerModification()
+ {
+ ASSERT(!m_modificationForbidden);
+ }
#else
- int64_t modifications() const { return 0; }
- void registerModification() {}
- void checkModifications(int64_t mods) const {}
+ void registerModification() { }
#endif
private:
@@ -569,14 +569,10 @@ private:
ValueType* m_table;
unsigned m_tableSize;
unsigned m_keyCount;
-#if ENABLE(ASSERT)
- unsigned m_deletedCount:30;
- unsigned m_queueFlag:1;
- unsigned m_accessForbidden:1;
- unsigned m_modifications;
-#else
unsigned m_deletedCount:31;
unsigned m_queueFlag:1;
+#if ENABLE(ASSERT)
+ unsigned m_modificationForbidden;
#endif
#if DUMP_HASHTABLE_STATS_PER_TABLE
@@ -596,8 +592,7 @@ inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
, m_deletedCount(0)
, m_queueFlag(false)
#if ENABLE(ASSERT)
- , m_accessForbidden(false)
- , m_modifications(0)
+ , m_modificationForbidden(0)
#endif
#if DUMP_HASHTABLE_STATS_PER_TABLE
, m_stats(adoptPtr(new Stats))
@@ -647,7 +642,6 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctio
template <typename HashTranslator, typename T>
inline const Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::lookup(const T& key) const
{
- ASSERT(!m_accessForbidden);
ASSERT((HashTableKeyChecker<HashTranslator, KeyTraits, HashFunctions::safeToCompareToEmptyOrDeleted>::checkKey(key)));
const ValueType* table = m_table;
if (!table)
@@ -687,7 +681,6 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctio
template <typename HashTranslator, typename T>
inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::lookupForWriting(const T& key)
{
- ASSERT(!m_accessForbidden);
ASSERT(m_table);
registerModification();
@@ -730,7 +723,6 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctio
template <typename HashTranslator, typename T>
inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::fullLookupForWriting(const T& key)
{
- ASSERT(!m_accessForbidden);
ASSERT(m_table);
registerModification();
@@ -801,7 +793,6 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctio
template <typename HashTranslator, typename T, typename Extra>
typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::add(T&& key, Extra&& extra)
{
- ASSERT(!m_accessForbidden);
ASSERT(Allocator::isAllocationAllowed());
if (!m_table)
expand();
@@ -867,7 +858,6 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctio
template <typename HashTranslator, typename T, typename Extra>
typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::addPassingHashCode(T&& key, Extra&& extra)
{
- ASSERT(!m_accessForbidden);
ASSERT(Allocator::isAllocationAllowed());
if (!m_table)
expand();
@@ -957,14 +947,7 @@ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
++m_stats->numRemoves;
#endif
- ASSERT(!m_accessForbidden);
-#if ENABLE(ASSERT)
- m_accessForbidden = true;
-#endif
deleteBucket(*pos);
-#if ENABLE(ASSERT)
- m_accessForbidden = false;
-#endif
++m_deletedCount;
--m_keyCount;
@@ -1100,15 +1083,7 @@ Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
}
newEntry = rehashTo(originalTable, newTableSize, newEntry);
- ASSERT(!m_accessForbidden);
-#if ENABLE(ASSERT)
- m_accessForbidden = true;
-#endif
deleteAllBucketsAndDeallocate(temporaryTable, oldTableSize);
-#if ENABLE(ASSERT)
- m_accessForbidden = false;
-#endif
-
return newEntry;
}
@@ -1178,15 +1153,7 @@ Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Alloca
ValueType* newTable = allocateTable(newTableSize);
Value* newEntry = rehashTo(newTable, newTableSize, entry);
- ASSERT(!m_accessForbidden);
-#if ENABLE(ASSERT)
- m_accessForbidden = true;
-#endif
deleteAllBucketsAndDeallocate(oldTable, oldTableSize);
-#if ENABLE(ASSERT)
- m_accessForbidden = false;
-#endif
-
return newEntry;
}
@@ -1197,14 +1164,7 @@ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
if (!m_table)
return;
- ASSERT(!m_accessForbidden);
-#if ENABLE(ASSERT)
- m_accessForbidden = true;
-#endif
deleteAllBucketsAndDeallocate(m_table, m_tableSize);
-#if ENABLE(ASSERT)
- m_accessForbidden = false;
-#endif
m_table = nullptr;
m_tableSize = 0;
m_keyCount = 0;
@@ -1218,8 +1178,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
, m_deletedCount(0)
, m_queueFlag(false)
#if ENABLE(ASSERT)
- , m_accessForbidden(false)
- , m_modifications(0)
+ , m_modificationForbidden(0)
#endif
#if DUMP_HASHTABLE_STATS_PER_TABLE
, m_stats(adoptPtr(new Stats(*other.m_stats)))
@@ -1241,8 +1200,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
, m_deletedCount(0)
, m_queueFlag(false)
#if ENABLE(ASSERT)
- , m_accessForbidden(false)
- , m_modifications(0)
+ , m_modificationForbidden(0)
#endif
#if DUMP_HASHTABLE_STATS_PER_TABLE
, m_stats(adoptPtr(new Stats(*other.m_stats)))
@@ -1255,7 +1213,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::H
template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::swap(HashTable& other)
{
- ASSERT(!m_accessForbidden);
+ registerModification();
std::swap(m_table, other.m_table);
std::swap(m_tableSize, other.m_tableSize);
std::swap(m_keyCount, other.m_keyCount);
@@ -1267,7 +1225,7 @@ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocato
ASSERT(!other.m_queueFlag);
#if ENABLE(ASSERT)
- std::swap(m_modifications, other.m_modifications);
+ std::swap(m_modificationForbidden, other.m_modificationForbidden);
#endif
#if DUMP_HASHTABLE_STATS_PER_TABLE
@@ -1290,6 +1248,45 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>& H
return *this;
}
+#if ENABLE(ASSERT)
+template <typename HashTableType>
+HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbiddenScope()
+ : m_container(nullptr)
+{
+}
+
+template <typename HashTableType>
+HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbiddenScope(const HashTableType* container)
+ : m_container(const_cast<HashTableType*>(container))
+{
+ if (m_container)
+ m_container->enterModificationForbiddenScope();
+}
+
+template <typename HashTableType>
+HashTableModificationForbiddenScope<HashTableType>::HashTableModificationForbiddenScope(const HashTableModificationForbiddenScope& other)
+ : m_container(other.m_container)
+{
+ if (m_container)
+ m_container->enterModificationForbiddenScope();
+}
+
+template <typename HashTableType>
+HashTableModificationForbiddenScope<HashTableType>::~HashTableModificationForbiddenScope()
+{
+ leaveScope();
+}
+
+template <typename HashTableType>
+void HashTableModificationForbiddenScope<HashTableType>::leaveScope()
+{
+ if (!m_container)
+ return;
+ m_container->leaveModificationForbiddenScope();
+ m_container = nullptr;
+}
+#endif
+
template <WeakHandlingFlag weakHandlingFlag, typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator>
struct WeakProcessingHashTableHelper;
« no previous file with comments | « no previous file | third_party/WebKit/Source/wtf/LinkedHashSet.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698