sdk: `dotnet run` gives `ArgumentOutOfRangeException` error at `TryGetTargetArchitecture` method

Describe the bug

I installed .NET 6.0.1 SDK, and turned out that I cannot use command dotnet run at all, because it keeps giving me ArgumentOutOfRangeException. However, it is successful to run dotnet build then dotnet [path-to-dll] or dotnet watch run instead. The full error message:

System.ArgumentOutOfRangeException: startIndex cannot be larger than length of string. (Parameter 'startIndex')
   at System.String.Substring(Int32 startIndex, Int32 length)
   at Microsoft.DotNet.Tools.Run.RunCommand.TryGetTargetArchitecture(String runtimeIdentifier, Nullable`1& targetArchitecture)
   at Microsoft.DotNet.Tools.Run.RunCommand.GetTargetCommand()
   at Microsoft.DotNet.Tools.Run.RunCommand.Execute()
   at Microsoft.DotNet.Tools.Run.RunCommand.Run(String[] args)
   at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)
   at Microsoft.DotNet.Cli.Program.Main(String[] args)

I have tried reinstalled using SDK Installer, Visual Studio Installer, and binaries zip file. All gave me the same result.

So I decided to pull the branch release/6.0.1xx from this repository, and modified the method TryGetTargetArchitecture in file src\Cli\dotnet\commands\dotnet-run\RunCommand.cs to add try&catch blocks as following to debug the behaviour of the command:

private static bool TryGetTargetArchitecture(string runtimeIdentifier, out Architecture? targetArchitecture)
{
    targetArchitecture = null;
    int separator = runtimeIdentifier.LastIndexOf("-");
    if (separator < 0)
    {
        return false;
    }

    try // ↓ MODIFIED FROM HERE
    {
        targetArchitecture = runtimeIdentifier.Substring(separator + 1).ToLowerInvariant() switch
        {
            "arm" => Architecture.Arm,
            "arm64" => Architecture.Arm64,
            "x64" => Architecture.X64,
            "x86" => Architecture.X86,
            _ => null
        };
    }
    catch
    {
        Console.WriteLine($"runtimeIdentifier = {runtimeIdentifier}");
        Console.WriteLine($"runtimeIdentifier.Length = {runtimeIdentifier.Length}");
        Console.WriteLine("runtimeIdentifier (CharArray) = " + String.Join(", ", runtimeIdentifier.ToCharArray().Select(x => $"'{x}'")));
        Console.WriteLine($"separator = {separator}");
    } // ↑ MODIFIED UNTIL HERE

    return targetArchitecture != null;
}

Here is the result:

runtimeIdentifier =
runtimeIdentifier.Length = 0
runtimeIdentifier (CharArray) =
separator = 0

runtimeIdentifier = win-x64
runtimeIdentifier.Length = 7
runtimeIdentifier (CharArray) = 'w', 'i', 'n', '-', 'x', '6', '4'
separator = 7

Oddly, it seems that String.LastIndexOf in my machine does not work as expected, and that cause it returns an incorrect character index.

I don’t know what in my machine breaks the LastIndexOf, but it would be better if we have a safer logic in this method to prevent the similar problem.


Further technical details

  • Include the output of dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.100
 Commit:    9e8b04bbff

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Users\xxx\exe\dotnet\sdk\6.0.100\

Host (useful for support):
  Version: 6.0.0
  Commit:  4822e3c3aa

.NET SDKs installed:
  6.0.100 [C:\Users\xxx\exe\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.0 [C:\Users\xxx\exe\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.0 [C:\Users\xxx\exe\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.0 [C:\Users\xxx\exe\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 15 (5 by maintainers)

Most upvoted comments

We should take the suggested fix as soon as possible - RIDs should always be parsed/manipulated in Invariant ways in the SDK. I’ve marked the issue as up-for-grabs if anyone from the community would like to contribute it. Tests would need to demonstrate that this function works for several different cultures set as the CurrentCulture/CurrentUICulture, ideally including several of those that use non-ASCII character sets, and some that use right-to-left encodings.

This issue still present as of .NET version 7.0.306. Might be time to reopen this up. i’m still not sure how much this would affect my workflow. Let’s hope for a minimal effect long-terms wise . I’m also Thai. So this issue must be something related to our localization encoding?

This document will help with SDK versioning. https://docs.microsoft.com/en-us/dotnet/core/porting/versioning-sdk-msbuild-vs Basically, the SDK matches the major version of .NET but does feature releases with VS hence the hybrid version numbers that don’t match either.

ถ้าผมถอยไปใช้.net version5 ความสามรถในการทำงานจะเหมือนกับตัว.net version6เลยไหมครับ?

ปล.โปรแกรมที่ผมต้องใช้คือ Visual Studio Codeครับ

have this error too

According to `LastIndexOf`` documentation here:

Note: This code example was executed on a console whose user interface 
culture is "en-US" (English-United States).

This code example produces the following results:

Find the last occurrence of a character using different values of StringComparison.
The current culture is "en-US" - English (United States).
Search for the string "Å" in the string "A Cheshire ca°t"

Part 1: Start index and count are specified.
Comparison: CurrentCulture               Location:  -1
Comparison: CurrentCultureIgnoreCase     Location:  12
Comparison: InvariantCulture             Location:  -1
Comparison: InvariantCultureIgnoreCase   Location:  12
Comparison: Ordinal                      Location:  -1
Comparison: OrdinalIgnoreCase            Location:  -1

Part 2: Start index is specified.
Comparison: CurrentCulture               Location:  -1
Comparison: CurrentCultureIgnoreCase     Location:  12
Comparison: InvariantCulture             Location:  -1
Comparison: InvariantCultureIgnoreCase   Location:  12
Comparison: Ordinal                      Location:  -1
Comparison: OrdinalIgnoreCase            Location:  -1

Part 3: Neither start index nor count is specified.
Comparison: CurrentCulture               Location:  -1
Comparison: CurrentCultureIgnoreCase     Location:  12
Comparison: InvariantCulture             Location:  -1
Comparison: InvariantCultureIgnoreCase   Location:  12
Comparison: Ordinal                      Location:  -1
Comparison: OrdinalIgnoreCase            Location:  -1

It seems that String.LastIndexOf behaves differently depends on locale, which in my case it is in Thai. So it should be instead as following to support users from different cultural environment:

int separator = runtimeIdentifier.LastIndexOf("-", StringComparison.InvariantCulture);

I have tried rebuilt with the above fix, and the command dotnet run now works in my machine.