-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
LINQ bug: ConcatNIterator.LazyToArray() produces incorrect results #23389
Comments
It does seem to be in Variant: var concat = new List<string> {"A"}.Concat(new List<object> {"B"}).Concat(new List<string> {"C"})
.Concat(new List<string>{"D"}).Concat(new List<string>{"E"});
Assert.Equal(new object[]{"A", "B", "C", "D", "E"}, concat.ToArray()); // Actual "A", "B", "A", "C", "D" Perhaps relevant that the objects added are not |
In the above, after |
@JonHanna You already seem to know the ins and outs of this issue. Since I'm working on a personal project right now, I'd be happy to let you handle it. Otherwise (since this is a bug, and I introduced it) I'll submit a PR within a few days. |
@JonHanna If this happens in any other places like ToList(), please be sure those functions are fixed too. |
This looks pretty bad - I wonder what is the impact of this bug. Which kind of scenarios is it going to show up? |
@jamesqo I'm phone-access only for a few hours at least, but I'll take a look if you haven't found it by then |
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 :) |
Looking into it. |
In LargeArrayBuilder.cs changing |
On the other hand, with it in the |
@JonHanna the root cause is |
Yeah, not finding the count should be sub-optimal, but still correct, and if it did get the count there'd still be cases that mixed cases that could and couldn't get it. |
That's the root cause:
This pattern (I'm finding it in a few spots) is not using |
@OmarTawfik beside having a fix (which is awesome btw), I would love to know what is the impact of this bug -- which scenarios will be impacted? How common they are? How hard it will be for affected developers to root cause it? (likely pretty hard) |
This pattern is used from |
@jamesqo basically, Since |
Spent some time investigating other possibilities. The following is a repro for [Fact]
public void ConcatListsProduceOrderedResults()
{
var results = new TestEnumerable<int> (new int[] { 1 })
.Concat(new List<int> { 2 })
.Concat(new TestEnumerable<int>(new int[] { 3 }))
.ToArray();
Assert.Equal("1 2 3", string.Join(' ', results)); // Produces 1 2 1
} And this is for [Fact]
public void AppendToNonCollectionToArrayOrderedResults()
{
var results = new int[] { 4, 5, 6 }
.SelectMany(i => i == 5
? (IEnumerable<int>)new List<int>() { i }
: new TestEnumerable<int>(new int[] { i }))
.ToArray();
Assert.Equal("4 5 6", string.Join(' ', results)); // Produces 4 5 4
} I didn't find a possible path for
|
On part one of that, the case of an enumerable having a count or length property through non-generic Of course the second issue which is not merely slower than possible, but incorrect, is not a matter of weighing likelihood of inputs. The assignment of zero to |
Hi everyone, I'm on mobile rn so I can't really write a lot. I see you guys are fretting over this and the code I wrote isn't the most straightforward to fix, so I will take a look asap and submit a fix when I'm around a computer. Thanks. |
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 |
I've put forth a prototype for fixing this issue at https://github.com/jamesqo/corefx/commit/c5699a03c0776346b696623b6c44c900db5f3945. Just have to run the tests... |
Thanks @jamesqo! |
@OmarTawfik Thanks for the regression tests, I'm going to use them in my upcoming PR. Luckily I don't think this bug happens with |
My group appears to have hit this as well while trying to move our project to netstandard2.0. We also hit it once with With With
and saw the same behavior where |
I think we should include the fix in 2.0.2 servicing release. |
I agree. cc: @karelz, @Petermarcu |
Can you please share a repro for your first example? That may be a separate bug on its own. As far as I can see, this bug should only incorrectly duplicate some items, e.g. in your second example |
Here is a repro (from @vuminhle). It seems very specific - reducing the list sizes or changing the construction in various ways loses the repro. using System;
using System.Collections.Generic;
using System.Linq;
namespace repro {
internal class Program {
private static void Main(string[] args) {
A[] list = List1().Concat(List2()).Concat(List3()).ToArray();
foreach (A a in list) {
Console.WriteLine(a.Value);
}
}
internal static IEnumerable<A> List1() {
for (var i = 0; i < 4; i++) {
yield return new A(i);
}
}
internal static IEnumerable<A> List2() {
return Enumerable.Range(0, 2).Select(v => new A(v));
}
internal static IEnumerable<A> List3() {
for (var i = 0; i < 5; i++) {
yield return new A(i);
}
}
internal class A {
public A(int v) {
Value = v;
}
public int Value { get; }
}
}
} |
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 |
…#23817) * Fix #23680 * PR Feedback * More tests * More tests
@OmarTawfik You can close this. I opened dotnet/corefx#23833 for the separate issue mentioned, which I intend to grab tmrw. |
It was reopened to track 2.0.x port in PR dotnet/corefx#23865 |
@karelz this can be closed right? |
Yes, now that the rel/2.0.0 PR is merged. |
…dotnet#23817) * Fix #23680 * PR Feedback * More tests * More tests
Context: https://github.com/dotnet/corefx/issues/23680 Fixes unit tests under iOS, macOS, and watchOS.
Context: https://github.com/dotnet/corefx/issues/23680 Fixes unit tests under iOS, macOS, and watchOS.
Here's a repro: https://github.com/gulbanana/repro-corefx-concat-toarray
The problem occurs when using Concat multiple times and then calling ToArray().
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 containing multiple subclass instances) but I've worked around the bug by using
ToList()
instead.[EDIT] Add C# syntax highlight by @karelz
The text was updated successfully, but these errors were encountered: