Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

  • Understand the issue: Enumerable.Concat() throws ArgumentOutOfRangeException when called after Skip() that skips more elements than exist
  • Explore the codebase to find the root cause
  • Fix the bug in IListSkipTakeIterator.Fill() method in SkipTake.SpeedOpt.cs
  • Address review feedback: Move bounds check inside span path and check sourceIndex against sourceSpan.Length
  • Address review feedback: Move test to SkipTests.cs with multiple source types and operators
  • Address review feedback: Add tests for Skip followed by Select, Where, Take, Distinct, OrderBy operators
  • Verify IndexOf method - already has bounds check, add Contains tests

Summary

Root Cause:
The IListSkipTakeIterator.Fill() method in SkipTake.SpeedOpt.cs called Span.Slice(sourceIndex, destination.Length) unconditionally. When Skip() skips more elements than exist, sourceIndex can be beyond the source span's length, causing Slice() to throw even though no elements need to be copied.

Regression: Introduced in PR #112401 ("Improve Enumerable.Skip and Enumerable.Take performance"), merged on February 13, 2025.

Fix:
Added bounds check sourceIndex < sourceSpan.Length inside the span path before calling Slice().

Note on IndexOf: The IndexOf method also added in PR #112401 already has a similar bounds check (minInclusive < span.Length) in the current codebase, so it's not affected by this bug.

Test:
Added comprehensive test in SkipTests.cs covering multiple source types (array, list, ReadOnlyCollection, ICollection, IReadOnlyCollection, enumerable) with various operators:

  • Concat, Append, ToArray, ToList
  • Select, Where, Take, Skip, Distinct, OrderBy
  • Contains (exercises IndexOf)

Security Summary:
No security vulnerabilities identified. The fix is a simple bounds check addition that prevents an unnecessary operation.

Original prompt

This section details on the original issue you should resolve

<issue_title>Enumerable.Concat() method throws an ArgumentOutOfRangeException if it is called after a Skip()</issue_title>
<issue_description>### Description

Enumerable.Concat() method throws an ArgumentOutOfRangeException if it is called after a Skip() method that has skipped more elements than exist.

Reproduction Steps

Program.cs:

using System.Linq;

var source = new int[] { 1 };
var items = new int[] { 2, 3 };

var result = source
    .Skip(2)
    .Concat(items)
    .ToArray();

csproj file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Expected behavior

result = [ 2, 3 ]

Actual behavior

A ArgumentOutOfRangeException is thrown:

System.ArgumentOutOfRangeException
  HResult=0x80131502
  Message=Specified argument was out of the range of valid values.
  Source=System.Private.CoreLib
  StackTrace:
   at System.ThrowHelper.ThrowArgumentOutOfRangeException()
   at System.ReadOnlySpan`1.Slice(Int32 start, Int32 length)
   at System.Linq.Enumerable.IListSkipTakeIterator`1.Fill(IList`1 source, Span`1 destination, Int32 sourceIndex)
   at System.Linq.Enumerable.IListSkipTakeIterator`1.CopyTo(TSource[] array, Int32 arrayIndex)
   at System.Linq.Enumerable.Concat2Iterator`1.ToArray()
   at Program.<Main>$(String[] args) in C:\Work\Projects\Tests\EnumerableIssue\Program.cs:line 7

Regression?

SDK 9.0.308: result = [ 2, 3 ]
SDK 10.0.102: System.ArgumentOutOfRangeException

Known Workarounds

If insert Select(x => x) method before the Concat(), it solves the problem.

Configuration

.NET SDK:
Version: 10.0.102
Commit: 4452502459
Workload version: 10.0.100-manifests.6d969a7e
MSBuild version: 18.0.7+445250245

Runtime Environment:
OS Name: Windows
OS Version: 10.0.26200
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\10.0.102\

Other information

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…ips more elements than exist

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ArgumentOutOfRangeException in Enumerable.Concat() method Fix ArgumentOutOfRangeException when Concat called after Skip that skips more elements than exist Jan 17, 2026
Copilot AI requested a review from stephentoub January 17, 2026 00:23
…ceSpan.Length

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…perators

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
… operators

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI requested a review from stephentoub January 17, 2026 21:52
@stephentoub stephentoub marked this pull request as ready for review January 18, 2026 16:09
Copilot AI review requested due to automatic review settings January 18, 2026 16:09
@dotnet-policy-service
Copy link
Contributor

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression introduced in .NET 10 where Enumerable.Skip() that skips more elements than exist in the source causes an ArgumentOutOfRangeException when followed by certain operators like Concat(), Append(), or when calling ToArray()/ToList().

Changes:

  • Added bounds check in Fill() method to prevent invalid span slicing when skip index exceeds source length
  • Added comprehensive regression test covering multiple source types and LINQ operators

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs Added bounds check sourceIndex < sourceSpan.Length before calling Slice() to prevent ArgumentOutOfRangeException
src/libraries/System.Linq/tests/SkipTests.cs Added comprehensive test that validates the fix across various source types (array, list, ReadOnlyCollection, etc.) and operators

Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can you tell if or when this regressed?

@eiriktsarpalis
Copy link
Member

@copilot can you answer my earlier question please?

Copy link
Contributor Author

Copilot AI commented Jan 19, 2026

@copilot can you answer my earlier question please?

Yes, this regressed in PR #112401 ("Improve Enumerable.Skip and Enumerable.Take performance"), merged on February 13, 2025. That PR added the TryGetSpan-based optimization in IListSkipTakeIterator.Fill() which uses Span.Slice(). The bug is that Slice() validates the start index even for zero-length slices, so when Skip() skips more elements than exist, the sourceIndex exceeds the span's length and throws ArgumentOutOfRangeException.

@eiriktsarpalis
Copy link
Member

@copilot judging by the diff in the PR that you cited, we're missing a similar fix in the IndexOf method? Could you try to address that and add relevant testing?

Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 19, 2026

@copilot judging by the diff in the PR that you cited, we're missing a similar fix in the IndexOf method? Could you try to address that and add relevant testing?

The IndexOf method already has the bounds check in the current codebase (if (minInclusive < span.Length)). Looking at PR #112401, the original code didn't have this check, so it appears someone fixed IndexOf at some point after that PR merged, but the Fill method was overlooked. I've added Contains tests (which exercise IndexOf) to the test coverage in 5d85ed8.

@stephentoub stephentoub merged commit 609e9be into main Jan 20, 2026
90 checks passed
@stephentoub stephentoub deleted the copilot/fix-enumerable-concat-error branch January 20, 2026 02:57
@snakefoot
Copy link
Contributor

snakefoot commented Jan 21, 2026

@stephentoub Any plans for including in 10.0.3 ?

@stephentoub
Copy link
Member

In 10.0.3, definitely not.

In a future servicing after that, possibly.

@jeffhandley?

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.

Enumerable.Concat() method throws an ArgumentOutOfRangeException if it is called after a Skip()

4 participants