Skip to content

Commit 52bc52c

Browse files
Fix hash collision in TypeMapLazyDictionary causing non-deterministic ArgumentException (#123502)
## Description `TypeMapping.GetOrCreateExternalTypeMapping` threw non-deterministic `ArgumentException` when type names hashed to the same value. For example, `"Windows.Media.Devices.Core.FrameFlashControl"` and `"Windows.Security.Credentials.PasswordCredential"` produce identical `GetHashCode()` results, causing collision on insertion. Root cause: `LazyExternalTypeDictionary` used `Dictionary<int, DelayedType>` keyed by `string.GetHashCode()` instead of the string itself. This matches the collision-safe approach already used in `LazyProxyTypeDictionary` but simplified since external type mappings don't require multi-value support. The fix addresses a design issue where hash collisions could occur. The existing test coverage is sufficient to validate the behavior. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: AaronRobinsonMSFT <30635565+AaronRobinsonMSFT@users.noreply.github.com>
1 parent 4b0b723 commit 52bc52c

File tree

1 file changed

+4
-8
lines changed

1 file changed

+4
-8
lines changed

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TypeMapLazyDictionary.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,11 @@ public unsafe Type GetOrLoadType()
317317
[RequiresUnreferencedCode("Lazy TypeMap isn't supported for Trimmer scenarios")]
318318
private sealed class LazyExternalTypeDictionary : LazyTypeLoadDictionary<string>
319319
{
320-
private static int ComputeHashCode(string key) => key.GetHashCode();
321-
322-
private readonly Dictionary<int, DelayedType> _lazyData = new();
320+
private readonly Dictionary<string, DelayedType> _lazyData = new();
323321

324322
protected override bool TryGetOrLoadType(string key, [NotNullWhen(true)] out Type? type)
325323
{
326-
int hash = ComputeHashCode(key);
327-
if (!_lazyData.TryGetValue(hash, out DelayedType? value))
324+
if (!_lazyData.TryGetValue(key, out DelayedType? value))
328325
{
329326
type = null;
330327
return false;
@@ -336,13 +333,12 @@ protected override bool TryGetOrLoadType(string key, [NotNullWhen(true)] out Typ
336333

337334
public void Add(string key, TypeNameUtf8 targetType, RuntimeAssembly fallbackAssembly)
338335
{
339-
int hash = ComputeHashCode(key);
340-
if (_lazyData.ContainsKey(hash))
336+
if (_lazyData.ContainsKey(key))
341337
{
342338
ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key);
343339
}
344340

345-
_lazyData.Add(hash, new DelayedType(targetType, fallbackAssembly));
341+
_lazyData.Add(key, new DelayedType(targetType, fallbackAssembly));
346342
}
347343
}
348344

0 commit comments

Comments
 (0)