Skip to content

Globalization Invariant Mode string compare issue #106828

@tracktownsoftware

Description

@tracktownsoftware

Description

When Globalization Invariant Mode is turned on in csproj:
  <InvariantGlobalization>true</InvariantGlobalization>

Then this is not always true for strings s1, s2 and s3 using the System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare method:
  if s1 < s2 and s2 < s3, it should follow that s1 < s3.

Reproduction Steps

This code is from https://github.com/tracktownsoftware/NET-GlobalizationInvariantMode-String-Compare-Bug

    internal class Program
    {
        static void Main(string[] args)
        {
            var s1 = "бал";
            var s2 = "Бан";
            var s3 = "Д";

            var ci = System.Globalization.CultureInfo.InvariantCulture.CompareInfo;

            // First we pass the 3 strings in upper case with no problems.
            Debug.Assert(ci.Compare(s1.ToUpper(), s2.ToUpper(), System.Globalization.CompareOptions.IgnoreCase) < 0);
            Debug.Assert(ci.Compare(s2.ToUpper(), s3.ToUpper(), System.Globalization.CompareOptions.IgnoreCase) < 0);
            Debug.Assert(ci.Compare(s1.ToUpper(), s3.ToUpper(), System.Globalization.CompareOptions.IgnoreCase) < 0);

            // Now we pass the strings without ToUpper() - theoretically yielding the same result.
            Debug.Assert(ci.Compare(s1, s2, System.Globalization.CompareOptions.IgnoreCase) < 0);
            Debug.Assert(ci.Compare(s2, s3, System.Globalization.CompareOptions.IgnoreCase) < 0);

            // if s1 < s2 and s2 < s3, it should follow that s1 < s3.
            // This assertion fails if the project is running in invariant-globalization mode.
            // It succeecds if not running in invariant-globalization mode.
            //
            // To run in invariant-globalization mode, add the following to the property group
            // in StringCompareBug.csproj:
            //              <InvariantGlobalization>true</InvariantGlobalization>
            Debug.Assert(ci.Compare(s1, s3, System.Globalization.CompareOptions.IgnoreCase) < 0);
        }
    }

Expected behavior

The last assertion should not FAIL:
Debug.Assert(ci.Compare(s1, s3, System.Globalization.CompareOptions.IgnoreCase) < 0);

Actual behavior

The last assertion FAILS:
Debug.Assert(ci.Compare(s1, s3, System.Globalization.CompareOptions.IgnoreCase) < 0);

Regression?

I don't know, but will investigate and report back.

Known Workarounds

Do not use InvariantGlobalization, but that is not an option we want to use.

Configuration

.NET 8.0.303
VS2022 17.10.5
Windows 11 Pro
23H2, 22631.4037

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions