Skip to content

Use more consistent argument validation in Immutable collection types#127157

Draft
Copilot wants to merge 17 commits intomainfrom
copilot/fix-range-checks-in-helpers
Draft

Use more consistent argument validation in Immutable collection types#127157
Copilot wants to merge 17 commits intomainfrom
copilot/fix-range-checks-in-helpers

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

  • Identify merge conflict in ImmutableArray_1.cs
  • Analyze both sides: our Requires.ValidateRange helper vs main's two-line overflow-safe check (both do the same validation)
  • Resolve conflict by keeping our Requires.ValidateRange call
  • Commit the merge

Copilot AI and others added 14 commits April 19, 2026 19:07
…ncy and overflow handling

Update range validation in Sort, GetRange, Reverse, CopyTo, BinarySearch,
and FindIndex methods across ImmutableArray, ImmutableList, and their
Builders to use the consistent pattern:
- Requires.Range(index >= 0 && index <= this.Count, nameof(index));
- Requires.Range(count >= 0 && (uint)(index + count) <= (uint)this.Count, nameof(count));

This ensures:
1. The correct parameter is reported as out of range (index vs count)
2. Overflow is handled via unsigned cast comparison
3. All methods use a consistent validation pattern

Add test coverage for range validation in all updated methods.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f96d676a-8dac-4803-a986-ffa3fa632c37

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Both public callers (ImmutableList<T> and ImmutableList<T>.Builder)
already validate arguments before delegating to Node.Sort and
Node.Reverse. The Node's own Requires.Range/NotNull calls are
therefore unreachable and can be converted to Debug.Assert.

For ImmutableList.Reverse(int, int), validation was previously only
in the Node — added Requires.Range to the public method to maintain
the public contract, then converted the Node's checks to Debug.Assert.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/38cf8f63-313a-4f03-b51a-7f322887754c

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…ter validation

Introduce Requires.ValidateRange(index, count, listCount, indexParameterName)
to consolidate the repeated index/count range validation pattern. Applied
across ImmutableList, Builder, and Node, replacing 10 duplicate two-line
Requires.Range pairs with single ValidateRange calls.

Also normalize whitespace so every validation block is followed by a blank
line before the method body.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c34e5da8-17ce-4dc8-b489-4316b2fce76b

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…lder

Replace duplicate index+count range validation pairs with the shared
ValidateRange helper in four locations:
- ImmutableArray_1.cs IndexOf (startIndex, count)
- ImmutableArray_1.cs Sort (index, count)
- ImmutableArray_1.Builder.cs IndexOf (startIndex, count)
- ImmutableArray_1.Builder.cs Sort (index, count)

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d4cf6216-8bd8-470d-becc-84c58ee08b67

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…to Debug.Assert

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3b4d1d4f-650f-475e-b3bf-7815be22bc4b

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…bug.Assert + uint cast

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3b4d1d4f-650f-475e-b3bf-7815be22bc4b

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…eReverseRange helper

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/781e992a-9b7f-4694-b96b-ad274867bc99

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…use single Range check for FindLastIndex(startIndex, match); remove Builder.LastIndexOf fast path

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c527b2ab-9167-426d-9181-4b2065835708

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…-list validation tests

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c527b2ab-9167-426d-9181-4b2065835708

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…and simplify IndexOf validation

Replace separate Requires.Range(arrayIndex >= 0) + Requires.Range(array.Length >= arrayIndex + count)
with combined Requires.Range(arrayIndex >= 0 && (uint)(arrayIndex + count) <= (uint)array.Length)
in 13 CopyTo locations across immutable collection types.

Also replace wasteful Requires.ValidateRange(index, this.Count - index, this.Count) in
ImmutableList<T>.Builder.IndexOf(T, int) with direct Requires.Range((uint)index <= (uint)this.Count).

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/6843c2b4-a169-4ebc-a8f8-eea958164182

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…tions

Add tests verifying that CopyTo with int.MaxValue arrayIndex correctly
throws ArgumentOutOfRangeException for:
- ImmutableDictionary/SortedDictionary (base test class)
- ImmutableDictionary/SortedDictionary Builder (base test class)
- ImmutableHashSet/SortedSet (base test class)
- ImmutableHashSet Builder
- ImmutableSortedSet Builder
- ImmutableSortedDictionary Keys/Values (KeysOrValuesCollectionAccessor)
- ImmutableList Builder IndexOf(T, int) with overflow index

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/6843c2b4-a169-4ebc-a8f8-eea958164182

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI self-assigned this Apr 20, 2026
Copilot AI review requested due to automatic review settings April 20, 2026 13:26
Copilot AI review requested due to automatic review settings April 20, 2026 13:26
@MihaZupan MihaZupan changed the title Replace two-line CopyTo range checks with single overflow-safe check and fix wasteful IndexOf validation Use more consistent argument validation in Immutable collection types Apr 20, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-collections
See info in area-owners.md if you want to be subscribed.

@MihaZupan
Copy link
Copy Markdown
Member

Follow-up to #124967 to fix more places to handle argument validation more consistently.
E.g. type.IndexOf(value, index: int.MaxValue, count: 5) should blame the index
or to handle overflow cases that would bypass the validation if both the index and count were individually in range, but negative when combined.

cc: @prozolic

… directly

In ImmutableArray<T> and ImmutableArray<T>.Builder, intermediate overloads
that compute count as Length/Count - startIndex were delegating to the
full overload which called ValidateRange on both index and count. Since
count derived from Length - index is guaranteed valid when index is valid,
the count validation was wasteful.

Extract private IndexOfCore/LastIndexOfCore helpers and have intermediate
overloads validate just the index before calling them directly, matching
the approach already used in ImmutableList<T>.Builder.IndexOf(T, int).

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/33415a3f-837b-4dd6-b39c-a9859f8736fe

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI requested review from MihaZupan and Copilot and removed request for Copilot April 20, 2026 14:06
@MihaZupan MihaZupan added this to the 11.0.0 milestone Apr 20, 2026
…te index directly"

This reverts commit 1ddc14e.

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 20, 2026 14:32
…cks-in-helpers

# Conflicts:
#	src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 20, 2026 16:33
@jkotas
Copy link
Copy Markdown
Member

jkotas commented Apr 20, 2026

Should we get rid of the Requires helper and switch to what we use everywhere else (ArgumentNullException.ThrowIfNull, etc.)?

@eiriktsarpalis
Copy link
Copy Markdown
Member

Should we get rid of the Requires helper and switch to what we use everywhere else (ArgumentNullException.ThrowIfNull, etc.)?

Good idea, sounds like something Copilot could complete easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants