Skip to content

Fix LINQ Append/Prepend GetCount overflow to throw OverflowException#123821

Merged
stephentoub merged 3 commits intomainfrom
copilot/optimize-linq-getcount-implementation
Jan 31, 2026
Merged

Fix LINQ Append/Prepend GetCount overflow to throw OverflowException#123821
stephentoub merged 3 commits intomainfrom
copilot/optimize-linq-getcount-implementation

Conversation

Copy link
Contributor

Copilot AI commented Jan 30, 2026

Description

Append and Prepend speed optimizations silently overflow when counting sequences with int.MaxValue elements, returning negative counts instead of throwing OverflowException. This diverges from Concat, which correctly throws on overflow.

var source = Enumerable.Repeat(0, int.MaxValue);
var appended = source.Append(1);
appended.Count();  // Before: -2147483648 | After: throws OverflowException

Note: This issue only affects the synchronous System.Linq library. System.Linq.AsyncEnumerable does not have equivalent GetCount optimizations and already handles overflow correctly in CountAsync.

Changes

  • AppendPrepend.SpeedOpt.cs: Added checked arithmetic to GetCount in both AppendPrepend1Iterator and AppendPrependN
  • AppendPrependTests.cs: Added 6 overflow test cases using MockCollection<T> to avoid memory allocation

Testing

All 28 tests in AppendPrependTests pass, including the 6 new overflow tests.

Original prompt

This section details on the original issue you should resolve

<issue_title>LINQ Append and Prepend in Count speed optimization can overflow</issue_title>
<issue_description>The Prepend and Append LINQ implementation contains a speed optimization for GetCount that can overflow. There are two speed optimizations, AppendPrepend1Iterator and AppendPrependN and both appear to have overflows in their GetCount implementation, and each implementation can overflow differently depending on if the source implementation has a GetCount speed optimization.

To demonstrate a few of the issues.

The following will print -2147483648, and overflows in AppendPrepend1Iterator

var source = Enumerable.Repeat(0, int.MaxValue);
var appended = source.Append(1);
Console.WriteLine(appended.Count());

The following will print -2147483647 and overflows in AppendPrependN:

var source = Enumerable.Repeat(0, int.MaxValue);
var appended = source.Append(1).Prepend(2);
Console.WriteLine(appended.Count());

Generally, GetCount throws an OverflowException when the count cannot be represented as a 32-bit integer.

For example, with Concat, this will throw OverflowException

var source = Enumerable.Repeat(0, int.MaxValue);
var appended = source.Concat([1]);
Console.WriteLine(appended.Count());

It seems like the Append and Prepend speed optimizations should used checked arithmetic in their GetCount implementations.</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.

…flow tests

Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
…arrays

Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix overflow in LINQ Append and Prepend GetCount optimization Fix LINQ Append/Prepend GetCount overflow to throw OverflowException Jan 30, 2026
Copilot AI requested a review from vcsjones January 30, 2026 23:24
@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.

@stephentoub stephentoub marked this pull request as ready for review January 31, 2026 03:43
Copilot AI review requested due to automatic review settings January 31, 2026 03:43
Copilot AI requested a review from stephentoub January 31, 2026 03:47
@stephentoub stephentoub enabled auto-merge (squash) January 31, 2026 03:47
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 silent integer overflow bug in LINQ's Append and Prepend operations where counting sequences with int.MaxValue elements would return negative counts instead of throwing OverflowException, which is the expected behavior consistent with Concat.

Changes:

  • Added checked arithmetic to GetCount methods in both AppendPrepend1Iterator and AppendPrependN classes to throw OverflowException on overflow
  • Added 6 comprehensive overflow test cases covering both iterator types and different source types (Iterator vs ICollection)
  • Introduced MockCollection<T> test helper to test overflow scenarios without allocating memory

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/AppendPrepend.SpeedOpt.cs Added checked arithmetic to 4 count calculations in GetCount methods to ensure overflow throws OverflowException
src/libraries/System.Linq/tests/AppendPrependTests.cs Added MockCollection<T> helper class and 6 overflow test cases covering all overflow scenarios in both AppendPrepend1Iterator and AppendPrependN

@stephentoub stephentoub merged commit 087c690 into main Jan 31, 2026
98 of 103 checks passed
@vcsjones vcsjones deleted the copilot/optimize-linq-getcount-implementation branch January 31, 2026 13:18
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.

LINQ Append and Prepend in Count speed optimization can overflow

3 participants