Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

[release/2.0] Port dictionary hang detection from 2.1 #18219

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/mscorlib/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2474,6 +2474,9 @@
<data name="InvalidOperation_CollectionCorrupted" xml:space="preserve">
<value>A prior operation on this collection was interrupted by an exception. Collection's state is no longer trusted.</value>
</data>
<data name="InvalidOperation_ConcurrentOperationsNotSupported" xml:space="preserve">
<value>Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.</value>
</data>
<data name="InvalidOperation_ConstructorNotAllowedOnInterface" xml:space="preserve">
<value>Interface cannot have constructors.</value>
</data>
Expand Down
15 changes: 15 additions & 0 deletions src/mscorlib/src/System/Collections/Generic/Dictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,19 @@ private int FindEntry(TKey key)

if (buckets != null)
{
int collisionCount = 0;
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next)
{
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;

if (collisionCount >= entries.Length)
{
// The chain of entries forms a loop; which means a concurrent update has happened.
// Break out of the loop and throw, rather than looping forever.
ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
}
collisionCount++;
}
}
return -1;
Expand Down Expand Up @@ -431,6 +440,12 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)
return false;
}
#if FEATURE_RANDOMIZED_STRING_HASHING
if (collisionCount >= entries.Length)
{
// The chain of entries forms a loop; which means a concurrent update has happened.
// Break out of the loop and throw, rather than looping forever.
ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
}
collisionCount++;
#endif
}
Expand Down
6 changes: 6 additions & 0 deletions src/mscorlib/src/System/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantH
throw GetInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
}

internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported()
{
throw GetInvalidOperationException(ExceptionResource.InvalidOperation_ConcurrentOperationsNotSupported);
}

internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array array, int offset, int count)
{
throw GetArraySegmentCtorValidationFailedException(array, offset, count);
Expand Down Expand Up @@ -525,6 +530,7 @@ internal enum ExceptionResource
InvalidOperation_HandleIsNotInitialized,
AsyncMethodBuilder_InstanceNotInitialized,
ArgumentNull_SafeHandle,
InvalidOperation_ConcurrentOperationsNotSupported,
}
}