Runtime: [System.Guid] Discrepancy when constructing same Guid from string or byte array

Created on 12 May 2019  Â·  8Comments  Â·  Source: dotnet/runtime

I recently noticed that when you construct a Guid from a byte array you might not get the exact same Guid you described, as it happens when it is constructed from a string. In particular the 8 bytes in the higher groups seem to be flipped (9dad turns to ad9d, etc).

        [Fact]
        public void TestGuidDiscrepancy()
        {
            var asString = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
            var asBytes = new byte[]
            {
                0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
                0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
            };

            var guid1 = new Guid(asString);
            var guid2 = new Guid(asBytes);

            Assert.Equal(guid1.ToString(), guid2.ToString());
        }
Uma.Uuid.Tests.GeneratorTest.TestGuidDiscrepancy

Assert.Equal() Failure
          ↓ (pos 0)
Expected: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Actual:   10b8a76b-ad9d-d111-80b4-00c04fd430c8
          ↑ (pos 0)
   at Uma.Uuid.Tests.GeneratorTest.TestGuidDiscrepancy() in GeneratorTest.cs:line 28



md5-de20e1a0d0f948605f5bcfc80ad47cd7



$ dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   2.2.203
 Commit:    e5bab63eca

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  16.04
 OS Platform: Linux
 RID:         ubuntu.16.04-x64
 Base Path:   /usr/share/dotnet/sdk/2.2.203/

Host (useful for support):
  Version: 2.2.4
  Commit:  f95848e524

.NET Core SDKs installed:
  2.2.203 [/usr/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.4 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
area-System.Runtime documentation

All 8 comments

the first 12 letters (00000000-0000) bit is in fact a 8-byte integer and 4-byte integer, not just 8 and 4 1-byte data I believe. Probably endianess thing.

e.g. 0x6b, 0xa7, 0xb8, 0x10 is 0x6BA7B810 when interpreted as integer on big-endian machines but 0x10B8A76b when interpreted as integer on little-endian machines. (i.e. x86-64 and ARM machines)

Though, is there a standard on the endianess when interpreting GUID/UUIDs? that wikipedia article seem to state this:

The binary encoding of UUIDs varies between systems. Many systems encode the UUID entirely in a big-endian format.

But also:

...Other systems, notably Microsoft's marshalling of UUIDs in their COM/OLE libraries, use a mixed-endian format, whereby the first three components of the UUID are little-endian, and the last two are big-endian.

assuming it's the latter case I think the behaviour is expected, however could it be useful to provide a way to interpret the GUIDs encoded in the former format?

Spot on, that's exactly what it's doing. Thanks!

I really believe this behavior should be more clearly mentioned[1] in the docs, because the string-based constructor interprets all the supported input formats as a whole big-endian bitstream, and the Guid(byte[]) one only states that the input must be A 16-element byte array containing values with which to initialize the GUID. You just don't expect it to work so differently, a remark and a few examples would be great.

[1] It is mentioned in the remarks of the Guid(Int32, Int16, Int16, Byte, Byte, Byte, Byte, Byte, Byte, Byte, Byte) constructor, but in a rather vague way.

@1ma perhaps you'd like to offer a PR for the docs? https://github.com/dotnet/dotnet-api-docs

I'll see if I can manage.

Since the ctor is behaving as designed, and the proposed documentation update would be in a different repository, I'm going to go ahead and close this issue.

Was this page helpful?
0 / 5 - 0 ratings