KEMBAR78
[Breaking change]: `Enumerable.Sum` can throw `OverflowException` for inputs that weren't throwing in the past. · Issue #37734 · dotnet/docs · GitHub
Skip to content

[Breaking change]: Enumerable.Sum can throw OverflowException for inputs that weren't throwing in the past. #37734

@eiriktsarpalis

Description

@eiriktsarpalis

Description

.NET 8 adds support for vectorization in the Enumerable.Sum methods where applicable. As a side-effect of that change, the vectorized implementation can change the order in which the different elements are added. While this should not change the final result in successful runs, it can result in unexpected OverflowException for certain sets of pathological inputs.

Version

.NET 8 Preview 7

Previous behavior

The code

Test(GetEnumerable1());           // Non-vectorizable
Test(GetEnumerable1().ToArray()); // Vectorizable
Test(GetEnumerable2());           // Non-vectorizable
Test(GetEnumerable2().ToArray()); // Vectorizable

static IEnumerable<int> GetEnumerable1()
{
    for (int i = 0; i < 32; ++i)
    {
        yield return 1_000_000_000;
        yield return -1_000_000_000;
    }
}

static IEnumerable<int> GetEnumerable2()
{
    for (int i = 0; i < 32; ++i)
    {
        yield return 100_000_000;
    }
    for (int i = 0; i < 32; ++i)
    {
        yield return -100_000_000;
    }
}

static void Test(IEnumerable<int> input)
{
    try
    {
        Console.WriteLine(input.Sum());
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.GetType().Name);
    }
}

Prints

0
0
OverflowException
OverflowException

New behavior

The same code prints

0
OverflowException
OverflowException
0

Type of breaking change

  • Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code may require source changes to compile successfully.
  • Behavioral change: Existing binaries may behave differently at run time.

Reason for change

Taking advantage of vectorization in LINQ APIs.

Recommended action

Assuming your code is impacted by the change, you could either

  1. Disabling vectorization altogether in your application by setting the DOTNET_EnableHWIntrinsic environment variable to 0 or
  2. Writing a custom Sum method that doesn't use vectorization:
    static int Sum(IEnumerable<int> values)
    {
        int acc = 0;
        foreach (int value in values)
        {
            checked { acc += value; }
        }
        return acc;
    }

Feature area

LINQ

Affected APIs

The Enumerable.Sum method group.


Associated WorkItem - 177282

Metadata

Metadata

Assignees

Labels

🏁 Release: .NET 8Work items for the .NET 8 release📌 seQUESTeredIdentifies that an issue has been imported into Quest.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions