runtime: LINQ bug: ConcatNIterator.LazyToArray() produces incorrect results
Here’s a repro: https://github.com/gulbanana/repro-corefx-concat-toarray
banana@forsyth MINGW64 /c/code/repro-corefx-concat-toarray (master)
$ dotnet run -f netcoreapp1.0
A B C
banana@forsyth MINGW64 /c/code/repro-corefx-concat-toarray (master)
$ dotnet run -f netcoreapp2.0
A B A
The problem occurs when using Concat multiple times and then calling ToArray().
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
class A { public override string ToString() => "A"; }
class B { public override string ToString() => "B"; }
class C { public override string ToString() => "C"; }
static void Main(string[] args)
{
var results = new List<A> { new A() }
.Concat(new List<object> { new B() })
.Concat(new List<C> { new C() })
.ToArray();
Console.WriteLine(string.Join(' ', results));
}
}
This program should print “A B C”, but it instead prints “A B A”. I believe the problem is in the specialised implementation of concatenation for 3±enumerables-of-collections. I ran into it in an actual project (an IEnumerable<BaseType> containing multiple subclass instances) but I’ve worked around the bug by using ToList() instead.
[EDIT] Add C# syntax highlight by @karelz
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 34 (33 by maintainers)
Commits related to this issue
- Fix LargeArrayBuilder.CopyTo returning incorrect end-of-copy position (#23817) * Fix #23680 * PR Feedback * More tests * More tests — committed to dotnet/corefx by OmarTawfik 7 years ago
- Fix LargeArrayBuilder.CopyTo returning incorrect end-of-copy position (#23865) * Fix LargeArrayBuilder.CopyTo returning incorrect end-of-copy position (#23817) * Fix #23680 * PR Feedback * M... — committed to dotnet/corefx by OmarTawfik 7 years ago
- Fix LargeArrayBuilder.CopyTo returning incorrect end-of-copy position (#23817) * Fix #23680 * PR Feedback * More tests * More tests — committed to mono/corefx by OmarTawfik 7 years ago
- Bump to mono/2017-10/ab882c0c Context: https://github.com/dotnet/corefx/issues/23680 — committed to jonpryor/xamarin-android by jonpryor 6 years ago
- Bump to mono/2017-10/ab882c0c Context: https://github.com/dotnet/corefx/issues/23680 Fixes unit tests under iOS, macOS, and watchOS. — committed to jonpryor/xamarin-android by jonpryor 6 years ago
- Bump to mono/2017-10/ab882c0c (#1219) Context: https://github.com/dotnet/corefx/issues/23680 Fixes unit tests under iOS, macOS, and watchOS. — committed to xamarin/xamarin-android by jonpryor 6 years ago
- Bump to mono/2017-10/ab882c0c (#1217) Context: https://github.com/dotnet/corefx/issues/23680 — committed to xamarin/xamarin-android by jonpryor 6 years ago
I think we should include the fix in 2.0.2 servicing release.
I’ve just realised this is what was causing a bug with a website I was porting from netfx to corefx, and finding it hard to reproduce because the order of the sources to the concatenation was non-deterministic and only sometimes in the order to trigger this, but I didn’t think that would matter to the bug. Easily worked around now I know what it is, so thanks for that, @gulbanana
@jamesqo
Here is a repro (from @vuminhle). It seems very specific - reducing the list sizes or changing the construction in various ways loses the repro.
I should be able to submit a fix tmrw for this. Thanks for all of the preliminary investigation @JonHanna and @OmarTawfik.
edit: After thinking about it in my mind for a while, I believe what’s happening is the
column = 0part is causing the returned CopyPosition (which is supposed to represent the position copied up to) to be inaccurate. In the example in @JonHanna’s 2nd comment, we should start copying after the null from (row 0, column 1) but instead do it from (row 0, column 0).My scenario is part of an ORM - assembling a list of “operations” all subclassing a common base. Since triggering the bug requires all of concat(), toarray() and multiple-subtypes, it probably isn’t common. It was very disconcerting though, seeing the knock-on effects when 1+1+1 was no longer equal to 3 😃
This looks pretty bad - I wonder what is the impact of this bug. Which kind of scenarios is it going to show up? @VSadov @OmarTawfik can you please dig into it as a priority? If it is impactful, we may need to fix it in 2.0 servicing.