Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/9.0-staging] Fix LINQ handling of iterator.Take(...).Last(...) #112714

Merged
merged 1 commit into from
Feb 21, 2025

Conversation

stephentoub
Copy link
Member

Backport of #112680 to release/9.0-staging

Customer Impact

  • Customer reported
  • Found internally

Code that does commonLINQOperators.Take(...).Last(), where certainLINQOperators are things like Range, Select, Where, etc., if the value passed to take is larger than the number of elements in the source, Last will throw an exception, and LastOrDefault will end up returning the default value rather than the actual last value. Essentially, the consumer can start operating on incorrect data or hit unexpected failures.

Regression

  • Yes
  • No

This was introduced accidentally in .NET 9 as part of a change that consolidated several internal abstractions in LINQ.

Testing

Revamped the LINQ tests to execute various combinations that lead to this, but also a bunch of other combinations to try to root out any other similar issues.

Risk

Low. The change is isolated to a single block and is now much better tested. Developers would have either been getting back erroneous results, or erroneous exceptions; it'd be difficult for someone to have taken a meaningful dependency on the bug.

When the Take amount is larger than the number of elements in the source `Iterator<T>`, Last ends up throwing an exception and LastOrDefault ends up returning the default value, rather than returning the last value in the taken region.

As part of fixing this, I sured up the tests to try to cover more such sequences of operations. In doing so, the tests got a lot slower, so I tracked down and fixed places where we were doing a lot of unnecessary work.
@stephentoub stephentoub added Servicing-consider Issue for next servicing release review area-System.Linq labels Feb 19, 2025
@stephentoub stephentoub added this to the 9.0.x milestone Feb 19, 2025
@Copilot Copilot bot review requested due to automatic review settings February 19, 2025 22:38
Copy link
Contributor

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

Choose a reason for hiding this comment

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

PR Overview

This pull request backports a fix to the LINQ implementation so that calls to iterator.Take(...).Last(...) now correctly return the actual last element rather than a default value or throwing an exception. Key changes include:

  • Adjusting a condition in the SkipTake speed‐optimized code to correctly select the proper branch when handling the last element.
  • Updating internal transformation helpers and test cases to use the new CreateSources method instead of IdentityTransforms.
  • Revising various test methods to improve coverage and consistency across different enumerable scenarios.

Reviewed Changes

File Description
src/libraries/System.Linq/tests/EnumerableTests.cs Updated transformation helpers and test cases to use CreateSources for more robust scenarios.
src/libraries/System.Linq/tests/SelectManyTests.cs Revised parameterized tests to use a fixed loop for testing multiple ranges.
src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs Changed a condition in the Take method to address an issue with incorrectly retrieving the last element.
Other test files Adjusted test expectations and minor refactorings for consistency in enumerable behavior.

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

Comments suppressed due to low confidence (1)

src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs:433

  • Changing the condition from '>= _minIndexInclusive' to '> _minIndexInclusive' directly affects branch selection for retrieving the last element. Please verify that this change correctly resolves the issue without introducing unintended side effects.
                    count > _minIndexInclusive)

Tip: Copilot code review supports C#, Go, Java, JavaScript, Markdown, Python, Ruby and TypeScript, with more languages coming soon. Learn more

@artl93 artl93 added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Feb 20, 2025
@artl93
Copy link
Member

artl93 commented Feb 20, 2025

Adding approved per-email with Steve

@stephentoub stephentoub merged commit 61d986c into dotnet:release/9.0-staging Feb 21, 2025
89 of 92 checks passed
@stephentoub stephentoub deleted the port112680 branch February 21, 2025 03:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Linq Servicing-approved Approved for servicing release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants