Skip to content

Hashset.TrimExcess(int capacity) corrupts hashset data structure #97947

Closed
@weltkante

Description

@weltkante

Description

HashSet.TrimExcess (introduced in #66426 for .NET 9) sets Count=Capacity even if it doesn't have as many items. The excess items are default initialized, including the internal state the HashSet uses (hashcode and freelist links). This corrupts the hashset data structure as iterating will yield the uninitialized items but direct lookup will not see them.

Reproduction Steps

var Set = new HashSet<int>(200);
for (int i = 50; i < 60; i++)
    Set.Add(i);

Console.WriteLine($"Set.Count = {Set.Count}");
Console.WriteLine($"Set.TrimExcess(20)");
Set.TrimExcess(20);

Console.WriteLine($"Set.Count = {Set.Count}");
Console.WriteLine($"Set.ToArray().Length = {Set.ToArray().Length}");
Console.WriteLine($"foreach (var item in set)");
foreach (var item in Set)
    Console.WriteLine($"  Set.Contains({item}) = {Set.Contains(item)}");

Expected behavior

Count remains as before the trimming.

Actual behavior

Count is increased to full capacity

Regression?

no, new API

Known Workarounds

don't use the method with a capacity > count (making the new API rather useless)

Configuration

.NET 9.0.0-preview.2.24080.1

Other information

No response

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions