runtime: Incorrect verification of type parameter constraints by CLR verifier

Probably invalid behavior of CLR verifier caused by default generic interface method while C# compiler telling that everything is OK:

static class Program
{
        private interface ILogEntry
        {
            long Index { get; }
        }

        private interface IAuditTrail<TRecord>
            where TRecord : class, ILogEntry
        {
            ValueTask AppendAsync<TRecordImpl>(TRecordImpl impl, CancellationToken token)
                where TRecordImpl : notnull, TRecord => new ValueTask();
        }

        private interface IRaftLogEntry : ILogEntry
        {
            long Term { get; }
        }

        private sealed class AuditTrail : IAuditTrail<IRaftLogEntry>
        {
        }

        private readonly struct EmptyLogEntry : IRaftLogEntry
        {
            long IRaftLogEntry.Term => 0L;

            long ILogEntry.Index => 0L;
        }

        static void Main(string[] args)
	{
            IAuditTrail<IRaftLogEntry> auditTrail = new AuditTrail();
            auditTrail.AppendAsync<EmptyLogEntry>(new EmptyLogEntry(), CancellationToken.None);
	 }
}

The exception is

System.Security.VerificationException
  HResult=0x8013150D
  Message=Method ConsoleApp1.Program+IAuditTrail`1[ConsoleApp1.Program+IRaftLogEntry].AppendAsync: type argument 'TRecordImpl' violates the constraint of type parameter 'TRecordImpl'.
  Source=ConsoleApp1
  StackTrace:
   at ConsoleApp1.Program.Main(String[] args)

If implementation of AppendAsync method moved to class instead of interface then everything is fine.

Version information:

  • .NET Core version 3.1.100
  • Windows 10 Enterprise 1809 64-bit

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (11 by maintainers)

Most upvoted comments

I ran into what I think is the same issue: here is my repro code.

`void Main() { ((IBuggy<int>)new Worky()).Foo<int>(); ((IBuggy<object>)new Worky2()).Foo<string>(); ((IBuggy<Open>)new Buggy()).Foo<Open>(); }

interface IBuggy<T1> { public void Foo<T2>() where T2 : T1 => Console.WriteLine($“Works for type: {typeof(T1)}”); } public class Worky : IBuggy<int> { } public class Worky2 : IBuggy<object> { } public class Buggy : IBuggy<Open> { } public class Open { }`

The output is: image