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

Fix bool.TryParse/Format on big-endian systems #65078

Merged
merged 1 commit into from
Feb 10, 2022
Merged

Fix bool.TryParse/Format on big-endian systems #65078

merged 1 commit into from
Feb 10, 2022

Conversation

uweigand
Copy link
Contributor

@uweigand uweigand commented Feb 9, 2022

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Feb 9, 2022
else
{
BinaryPrimitives.WriteUInt64BigEndian(MemoryMarshal.AsBytes(destination), 0x460061006C0073); // "Fals"
}
Copy link
Member

@EgorBo EgorBo Feb 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, wasn't .WriteUInt64LittleEndian supposed to handle endianess via ReverseEndianness() for value?

        /// <summary>
        /// Write a UInt64 into a span of bytes as little endian.
        /// </summary>
        [CLSCompliant(false)]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void WriteUInt64LittleEndian(Span<byte> destination, ulong value)
        {
            if (!BitConverter.IsLittleEndian)
            {
                value = ReverseEndianness(value);
            }
            MemoryMarshal.Write(destination, ref value);
        }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it wasn't then you can re-write code to just MemoryMarshal.Write(destination, 0x73006C00610046); I guess

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that you need to distinguish between swapping the order of the characters and the order of the bytes within one two-byte character. See #64782 (comment) for an example. There's no single store that does the correct thing for both of these simultaneously on both big- and little-endian platforms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks for explanation! anyway maybe it's still better to use

MemoryMarshal.Write(destination, IsLittleEndian ? 0x73006C00610046 : ...)

?
less verbose IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work as well. I can try this out if you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patch updated accordingly.

@ghost
Copy link

ghost commented Feb 9, 2022

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

Issue Details

CC @stephentoub

Author: uweigand
Assignees: -
Labels:

area-System.Runtime, community-contribution

Milestone: -

@jkotas jkotas merged commit b2eba58 into dotnet:main Feb 10, 2022
Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing.

Are we running the regex tests on the s390x? I would expect it's going to have similar problems.

@uweigand uweigand deleted the fix-boolfmt branch February 11, 2022 08:29
@uweigand
Copy link
Contributor Author

Are we running the regex tests on the s390x? I would expect it's going to have similar problems.

Do you mean these tests (part of libs.tests):

     System.Text.RegularExpressions.Generators.Tests  Total: 164, Errors: 0, Failed: 0, Skipped: 0, Time: 6.729s
     System.Text.RegularExpressions.Tests  Total: 14829, Errors: 0, Failed: 0, Skipped: 0, Time: 59.637s

Those seem to be all good now ...

@stephentoub
Copy link
Member

Those seem to be all good now ...

Thanks for looking. I think there's actually still an issue there, but it's masked by limitations in our test infrastructure. .NET 7 includes a source generator for regex, where the generator will emit into the .dll the code for the regex implementation. I expect if you were to take a .dll compiled on a little-endian machine and run it on the s390x, or vice versa, you'd see operations fail.

Can you try compiling this program using a .NET 7 SDK on a little-endian machine:

using System.Text.RegularExpressions;

partial class Program
{
    public static void Main() => Console.WriteLine(Example().IsMatch(@"1abcd"));

    [RegexGenerator(@"\dabcd")]
    public static partial Regex Example();
}

and then running the resulting program on the big-endian one? It should print true, but I'm betting it's going to print false.

I'll prepare a fix for it, but I'm going to need your help in validating its correctness.

@uweigand
Copy link
Contributor Author

Thanks for looking. I think there's actually still an issue there, but it's masked by limitations in our test infrastructure. .NET 7 includes a source generator for regex, where the generator will emit into the .dll the code for the regex implementation. I expect if you were to take a .dll compiled on a little-endian machine and run it on the s390x, or vice versa, you'd see operations fail.

I see.

It should print true, but I'm betting it's going to print false.

Yes, this is indeed what happens.

I'll prepare a fix for it, but I'm going to need your help in validating its correctness.

Sure, happy to help! Thanks for thinking of this.

@stephentoub
Copy link
Member

I'll prepare a fix for it, but I'm going to need your help in validating its correctness.

Sure, happy to help! Thanks for thinking of this.

I ended up just deleting the offending code instead.

@uweigand
Copy link
Contributor Author

I'll prepare a fix for it, but I'm going to need your help in validating its correctness.

Sure, happy to help! Thanks for thinking of this.

I ended up just deleting the offending code instead.

I repeated the test above using today's snapshot (dotnet-sdk-7.0.100-preview.2.22118.2-linux-x64.tar.gz) to build the regex test case on Intel, and can confirm that the resulting assembly now outputs "True" when run on s390x.

Thanks!

@stephentoub
Copy link
Member

Thanks for confirming, @uweigand.

@ghost ghost locked as resolved and limited conversation to collaborators Mar 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RemoteExecutor: String 'True' was not recognized as a valid Boolean.
5 participants