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

The StringBuilder.Append(Char[], Int32, Int32) method call throws the System.ArgumentOutOfRange exception in a valid situation when the app targets .NET 8 and built in the Release configuration #96839

Closed
e1em3ntoDX opened this issue Jan 11, 2024 · 6 comments
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@e1em3ntoDX
Copy link

e1em3ntoDX commented Jan 11, 2024

Description

Hi,

We use a similar code in one of the DevExpress products and our customer stumbled upon an exception being thrown once they updated their project to .NET 8. The exception occurs when the stringBuilder.Append(array, array.Length - 2, 2); line of code is executed within a loop on the 10000th step and only in the Release configuration. We suppose that this might occur due to the some optimizations performed at a compile time in the Release mode.

    static char[] Digits = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    private void button1_Click(object sender, EventArgs e) {
        Test();
    }

    void Test() {
        for(int i = 0; i < 10000; i++) {

            var time = DateTime.Now;
            int year = time.Year;
            char[] array = NumberToString(year);

            StringBuilder stringBuilder = new StringBuilder();

            if(array.Length > 2) {
                stringBuilder.Append(array, array.Length - 2, 2);
            }
            else {
                stringBuilder.Append(array);
            }
        }
    }
    
    char[] NumberToString(int value) {
        byte num = 1;
        if(value != 0) {
            num += (byte)Math.Log10(value);
        }
        char[] array = new char[num];
        while(num > 0) {
            array[--num] = Digits[value % 10];
            value /= 10;
        }
        return array;
    }

Clipboard-File-2
WinFormsApp7.zip

Reproduction Steps

Use the code snippet above or the attached sample to reproduce the issue in an app built for AnyCPU/x64, .NET 8, in the Release mode.

Expected behavior

The exception is not thrown on the latest step of the loop.

Actual behavior

The exception is thrown on the latest step of the loop.

Regression?

Yes, this did work as expected in .NET 7 (tested on 7.0.14) and in .NET Framework.

Known Workarounds

No response

Configuration

  • .NET Runtime 8.0.1
  • .NET SDK 8.0.101
  • Windows 11, 22H2 (Build 22621.3007)
  • AnyCPU/x64
  • Release project configuration

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jan 11, 2024
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jan 11, 2024
@danmoseley danmoseley added area-System.Runtime and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jan 11, 2024
@ghost
Copy link

ghost commented Jan 11, 2024

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

Issue Details

Description

Hi,

We use a similar code in one of the DevExpress products and our customer stumbled upon an exception being thrown once they updated their project to .NET 8. The exception occurs when the stringBuilder.Append(array, array.Length - 2, 2); line of code is executed within a loop on the 10000th step and only in the Release configuration. We suppose that this might occur due to the some optimizations performed at a compile time in the Release mode.

`static char[] Digits = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    private void button1_Click(object sender, EventArgs e) {
        Test();
    }

    void Test() {
        for(int i = 0; i < 10000; i++) {

            var time = DateTime.Now;
            int year = time.Year;
            char[] array = NumberToString(year);

            StringBuilder stringBuilder = new StringBuilder();

            if(array.Length > 2) {
                stringBuilder.Append(array, array.Length - 2, 2);
            }
            else {
                stringBuilder.Append(array);
            }
        }
    }
    
    char[] NumberToString(int value) {
        byte num = 1;
        if(value != 0) {
            num += (byte)Math.Log10(value);
        }
        char[] array = new char[num];
        while(num > 0) {
            array[--num] = Digits[value % 10];
            value /= 10;
        }
        return array;
    }`

Clipboard-File-2
WinFormsApp7.zip

Reproduction Steps

Use the code snippet above or the attached sample to reproduce the issue in an app built for AnyCPU/x64, .NET 8, in the Release mode.

Expected behavior

The exception is not thrown on the latest step of the loop.

Actual behavior

The exception is thrown on the latest step of the loop.

Regression?

Yes, this did work as expected in .NET 7 (tested on 7.0.14) and in .NET Framework.

Known Workarounds

No response

Configuration

  • .NET Runtime 8.0.1
  • .NET SDK 8.0.101
  • Windows 11, 22H2 (Build 22621.3007)
  • AnyCPU/x64
  • Release project configuration

Other information

No response

Author: e1em3ntoDX
Assignees: -
Labels:

area-System.Runtime, untriaged

Milestone: -

@jkotas jkotas added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 11, 2024
@ghost
Copy link

ghost commented Jan 11, 2024

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Hi,

We use a similar code in one of the DevExpress products and our customer stumbled upon an exception being thrown once they updated their project to .NET 8. The exception occurs when the stringBuilder.Append(array, array.Length - 2, 2); line of code is executed within a loop on the 10000th step and only in the Release configuration. We suppose that this might occur due to the some optimizations performed at a compile time in the Release mode.

`static char[] Digits = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    private void button1_Click(object sender, EventArgs e) {
        Test();
    }

    void Test() {
        for(int i = 0; i < 10000; i++) {

            var time = DateTime.Now;
            int year = time.Year;
            char[] array = NumberToString(year);

            StringBuilder stringBuilder = new StringBuilder();

            if(array.Length > 2) {
                stringBuilder.Append(array, array.Length - 2, 2);
            }
            else {
                stringBuilder.Append(array);
            }
        }
    }
    
    char[] NumberToString(int value) {
        byte num = 1;
        if(value != 0) {
            num += (byte)Math.Log10(value);
        }
        char[] array = new char[num];
        while(num > 0) {
            array[--num] = Digits[value % 10];
            value /= 10;
        }
        return array;
    }`

Clipboard-File-2
WinFormsApp7.zip

Reproduction Steps

Use the code snippet above or the attached sample to reproduce the issue in an app built for AnyCPU/x64, .NET 8, in the Release mode.

Expected behavior

The exception is not thrown on the latest step of the loop.

Actual behavior

The exception is thrown on the latest step of the loop.

Regression?

Yes, this did work as expected in .NET 7 (tested on 7.0.14) and in .NET Framework.

Known Workarounds

No response

Configuration

  • .NET Runtime 8.0.1
  • .NET SDK 8.0.101
  • Windows 11, 22H2 (Build 22621.3007)
  • AnyCPU/x64
  • Release project configuration

Other information

No response

Author: e1em3ntoDX
Assignees: -
Labels:

area-System.Runtime, area-CodeGen-coreclr, untriaged

Milestone: -

@jakobbotsch
Copy link
Member

Thanks for the great minimized test case! I am able to reproduce the issue even on main. It does not repro with DOTNET_TC_OnStackReplacement=0, cc @AndyAyersMS

@jakobbotsch
Copy link
Member

It does repro with DOTNET_TC_OnStackReplacement=0 if you allow it to tier up naturally, so it is potentially inlining related.

@JulieLeeMSFT JulieLeeMSFT added this to the 9.0.0 milestone Jan 13, 2024
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jan 13, 2024
@EgorBo
Copy link
Member

EgorBo commented May 3, 2024

it doesn't repro on Main (9.0) 🤔

@EgorBo
Copy link
Member

EgorBo commented May 3, 2024

@jakobbotsch identified #100848 as a fix for this issue. it was recently backported to 8.0 so I guess we can close it

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

No branches or pull requests

6 participants