4

After upgrading one of my applications from .Net Core 3.1 to .Net 5 I am noticing weird failures in the parts of my code dealing with byte array serialization and MD5 hashes.

The code worked just fine in .Net Core 3.1, but after the upgrade to .Net 5 I am seeing issues at runtime when running on Linux.

Specifically the code hashes an object to a GUID as seen below:

        public Guid GenerateKey(string id, DateTime date1, DateTime? date2, string environment, string currencyCode, string ns, Dictionary<string, string> buildVersions)
        {
            var buildVersionString = string.Join(',', buildVersions.OrderBy(bv => bv.Key).Select(bv => $"{bv.Key}:{bv.Value}"));

            var key = new Key(id, date1, date2, environment, currencyCode, ns, buildVersionString); 

            var str = JsonConvert.SerializeObject(key);
            var bytes = Encoding.UTF8.GetBytes(str);

            var hashBytes = ComputeHash(bytes);

            return new Guid(hashBytes);
        }

        private byte[] ComputeHash(byte[] bytes)
        {
           using(var md5Hasher = MD5.Create())
           {
               return md5Hasher.ComputeHash(bytes);
           }     
        }

In .Net 3.1 I was able to generate multiple Guids using a simple ToDictionary call:

            var storedContents = new Content();

            storedContents.Keys = request.Ids.ToDictionary(
                                  k => k,
                                  v => keyProvider.GenerateKey(
                                  v,
                                  request.Date1,
                                  request.Date2,
                                  request.Environment,
                                  request.CurrencyCode,
                                  request.Namespace,
                                  request.BuildVersions)
            );

But in .Net 5 this started failing with the error below. The weird part is that it doesn't fail all the time, but fails pretty reliably after making a few requests.

Entry point was not found.
         at System.Collections.Generic.IEnumerable`1.GetEnumerator()
         at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source, Int32& length)
         at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
         at System.Linq.OrderedEnumerable`1.GetEnumerator()+MoveNext()
         at System.Linq.Enumerable.SelectIPartitionIterator`2.MoveNext()
         at System.String.JoinCore[T](Char* separator, Int32 separatorLength, IEnumerable`1 values)
         at POC.KeyProvider.GenerateKey(String id, DateTime date1, Nullable`1 date2, String environment, String currencyCode, String ns, Dictionary`2 buildVersions) in /home/tor/development/bug-repro/Api/POC/KeyProvider.cs:line 27
         at POC.StorageProvider.<>c__DisplayClass2_0.<GetContent>b__1(String v) in /home/tor/development/bug-repro/Api/POC/StorageProvider.cs:line 44
         at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](TSource[] source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
         at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
         at POC.StorageProvider.GetContent(MyRequest request) in /home/tor/development/bug-repro/Api/POC/StorageProvider.cs:line 42
         at Api.Controllers.TestController.Get() in /home/tor/development/bug-repro/Api/Controllers/TestController.cs:line 44
         at lambda_method7(Closure , Object , Object[] )

For some reason I am able to get it to work by converting the ToDictionary to a traditional foreach loop.

            storedContents.Keys = new Dictionary<string, System.Guid>();

            foreach(var id in request.Ids)
            {
                var key = keyProvider.GenerateKey(
                       id,
                       request.Date1,
                       request.Date2,
                       request.Environment,
                       request.CurrencyCode,
                       request.Namespace,
                       request.BuildVersions
                    );

                storedContents.Keys.Add(id, key);
            }

It seems like both versions should work, and did in .Net Core 3.1, but in .Net 5 the dictionary approach stopped working. Any thoughts on why this would break in .Net 5 on Linux? Windows seems fine, at least locally on my developer machine.

I have a reproduction of the issue here: https://github.com/thelgevold/Net5-Error

Note: In this example I am using NewtonSoft's JsonConvert.SerializeObject. I am seeing the same exact issue when using MessagePack for the serialization.

poke
  • 369,085
  • 72
  • 557
  • 602
TGH
  • 38,769
  • 12
  • 102
  • 135
  • 1
    Please share a [mcve]. – mjwills May 10 '21 at 01:53
  • Have a look at [Entry point was not found exception](https://stackoverflow.com/questions/13154241/entry-point-was-not-found-exception), according to that make sure the migration all correct. – Gellio Gao May 10 '21 at 01:59
  • @TGH I copied and pasted the code from the question and it wouldn't run as is. It isn't yet a [mcve]. – mjwills May 10 '21 at 02:00
  • You aren't sorting your properties. What's telling it to use the same order *every time* when it serializes the `Key` object? You should sort your properties as you serialize them to guarantee you get the same hash every time. Take a look at [this](https://stackoverflow.com/questions/3330989/order-of-serialized-fields-using-json-net). – Andy May 10 '21 at 02:52
  • @Andy I think that is good point, but I don't think that is the reason why it's failing though, In my real case I am actually using MessagePack with the contractless resolver. I see the same issue there, but decided to show the example with the JSON serializer to avoid too many external deps. – TGH May 10 '21 at 03:25

1 Answers1

1

There is a fix in .Net 5.0.6 for this problem.

See Github issue https://github.com/dotnet/runtime/issues/52539

TGH
  • 38,769
  • 12
  • 102
  • 135