Runtime: System.Security.VerificationException (type argument violates the constraint of type parameter) when running code on net 5.0

Created on 4 Dec 2020  路  4Comments  路  Source: dotnet/runtime

Description

Hi, we have encountered strange exception after one of ours project's target framework has been upgraded from netcoreapp3.1 to net5.0.

This is the exception message:

Unhandled exception. System.Security.VerificationException: Method ConsoleApp1.ComponentRegistry`1[ConsoleApp1.NamedObjectComponent`1[TNamedObject]].Register: type argument 'TComponentA' violates the constraint of type parameter 'TComponent'.
   at ConsoleApp1.SingleTypeNamedObjectContainer`1.Register[TComponentA]()
   at ConsoleApp1.NamedObjectContainer.Register[TNamedObject,TComponent]() in /Users/gureev/RiderProjects/ConsoleApp1/ConsoleApp1/Program.cs:line 87
   at ConsoleApp1.Program.Main(String[] args) in /Users/gureev/RiderProjects/ConsoleApp1/ConsoleApp1/Program.cs:line 108

I made simple console app to reproduce it:

    class Program
    {
        public abstract class NamedObject { }

        public class FooNamedObject : NamedObject { }

        public abstract class NamedObjectComponent { }

        public abstract class NamedObjectComponent<TNamedObject> : NamedObjectComponent where TNamedObject : NamedObject { }

        public class FooNamedObjectComponent : NamedObjectComponent<FooNamedObject> { }

        public abstract class SingleTypeNamedObjectContainer
        {
            internal SingleTypeNamedObjectContainer() { }

            internal abstract Type NamedObjectType { get; }
        }

        public class SingleTypeNamedObjectContainer<TNamedObject> : SingleTypeNamedObjectContainer
            where TNamedObject : NamedObject
        {
            private readonly ComponentRegistry<NamedObjectComponent<TNamedObject>> components =
                new ComponentRegistry<NamedObjectComponent<TNamedObject>>();

            internal override Type NamedObjectType => typeof(TNamedObject);

            public void Register<TComponentA>()
                where TComponentA : NamedObjectComponent<TNamedObject>, new()
            {
                components.Register<TComponentA>();
            }
        }

        public class ComponentRegistry<TBaseComponent> where TBaseComponent : class
        {
            private readonly HashSet<Type> componentTypes = new HashSet<Type>();

            private readonly Dictionary<Type, Func<TBaseComponent>> componentFactories =
                new Dictionary<Type, Func<TBaseComponent>>();

            public void Register<TComponent>()
                where TComponent : class, TBaseComponent, new()
            {
                Register(() => new TComponent());
            }

            public void Register<TComponent>(Func<TComponent> componentFactory)
                where TComponent : class, TBaseComponent
            {
                componentTypes.Add(typeof(TComponent));
                componentFactories.Add(typeof(TComponent), componentFactory);
            }
        }

        public class NamedObjectContainer
        {
            private readonly Dictionary<Type, SingleTypeNamedObjectContainer> subcontainersByNamedObjectType =
                new Dictionary<Type, SingleTypeNamedObjectContainer>();

            private readonly Dictionary<Type, SingleTypeNamedObjectContainer> subcontainersByRegisteredType =
                new Dictionary<Type, SingleTypeNamedObjectContainer>();

            public SingleTypeNamedObjectContainer<TNamedObject> RegisterNamedObjectType<TNamedObject>()
                where TNamedObject : NamedObject
            {
                return RegisterSubcontainer(new SingleTypeNamedObjectContainer<TNamedObject>());
            }

            public TSubcontainer RegisterSubcontainer<TSubcontainer>(TSubcontainer subcontainer)
                where TSubcontainer : SingleTypeNamedObjectContainer
            {
                subcontainersByNamedObjectType.Add(subcontainer.NamedObjectType, subcontainer);
                subcontainersByRegisteredType.Add(typeof(TSubcontainer), subcontainer);
                return subcontainer;
            }

            internal void Register<TNamedObject, TComponent>()
                where TNamedObject : NamedObject
                where TComponent : NamedObjectComponent<TNamedObject>, new()
            {
                GetSubcontainerFor<TNamedObject>().Register<TComponent>();
            }

            public SingleTypeNamedObjectContainer<TNamedObject> GetSubcontainerFor<TNamedObject>()
                where TNamedObject : NamedObject
            {
                return (SingleTypeNamedObjectContainer<TNamedObject>)GetSubcontainerFor(typeof(TNamedObject));
            }

            public SingleTypeNamedObjectContainer GetSubcontainerFor(Type baseNamedObjectType)
            {
                return subcontainersByNamedObjectType[baseNamedObjectType];
            }
        }

        static void Main(string[] args)
        {
            var contaner = new NamedObjectContainer();
            contaner.RegisterNamedObjectType<FooNamedObject>();
            contaner.Register<FooNamedObject, FooNamedObjectComponent>();
        }       
    }

If you run this code with target netcoreapp3.1 - it works.
But if you run with target netcoreapp5.0 - exception throws.

Configuration

Dotnet sdk 5.0.100
OS: MacOS Catalina (x64), Windows 10 1903 (x64)

Regression?

Yes, works on 3.1.

area-TypeSystem-coreclr untriaged

Most helpful comment

Let me run the repro locally and see where the exception stems from in the native runtime.

All 4 comments

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

Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq
See info in area-owners.md if you want to be subscribed.


Issue Details

Description

Hi, we have encountered strange exception after one of ours project's target framework has been upgraded from netcoreapp3.1 to net5.0.

This is the exception message:

Unhandled exception. System.Security.VerificationException: Method ConsoleApp1.ComponentRegistry`1[ConsoleApp1.NamedObjectComponent`1[TNamedObject]].Register: type argument 'TComponentA' violates the constraint of type parameter 'TComponent'.
   at ConsoleApp1.SingleTypeNamedObjectContainer`1.Register[TComponentA]()
   at ConsoleApp1.NamedObjectContainer.Register[TNamedObject,TComponent]() in /Users/gureev/RiderProjects/ConsoleApp1/ConsoleApp1/Program.cs:line 87
   at ConsoleApp1.Program.Main(String[] args) in /Users/gureev/RiderProjects/ConsoleApp1/ConsoleApp1/Program.cs:line 108

I made simple console app to reproduce it:

    class Program
    {
        public abstract class NamedObject { }

        public class FooNamedObject : NamedObject { }

        public abstract class NamedObjectComponent { }

        public abstract class NamedObjectComponent<TNamedObject> : NamedObjectComponent where TNamedObject : NamedObject { }

        public class FooNamedObjectComponent : NamedObjectComponent<FooNamedObject> { }

        public abstract class SingleTypeNamedObjectContainer
        {
            internal SingleTypeNamedObjectContainer() { }

            internal abstract Type NamedObjectType { get; }
        }

        public class SingleTypeNamedObjectContainer<TNamedObject> : SingleTypeNamedObjectContainer
            where TNamedObject : NamedObject
        {
            private readonly ComponentRegistry<NamedObjectComponent<TNamedObject>> components =
                new ComponentRegistry<NamedObjectComponent<TNamedObject>>();

            internal override Type NamedObjectType => typeof(TNamedObject);

            public void Register<TComponentA>()
                where TComponentA : NamedObjectComponent<TNamedObject>, new()
            {
                components.Register<TComponentA>();
            }
        }

        public class ComponentRegistry<TBaseComponent> where TBaseComponent : class
        {
            private readonly HashSet<Type> componentTypes = new HashSet<Type>();

            private readonly Dictionary<Type, Func<TBaseComponent>> componentFactories =
                new Dictionary<Type, Func<TBaseComponent>>();

            public void Register<TComponent>()
                where TComponent : class, TBaseComponent, new()
            {
                Register(() => new TComponent());
            }

            public void Register<TComponent>(Func<TComponent> componentFactory)
                where TComponent : class, TBaseComponent
            {
                componentTypes.Add(typeof(TComponent));
                componentFactories.Add(typeof(TComponent), componentFactory);
            }
        }

        public class NamedObjectContainer
        {
            private readonly Dictionary<Type, SingleTypeNamedObjectContainer> subcontainersByNamedObjectType =
                new Dictionary<Type, SingleTypeNamedObjectContainer>();

            private readonly Dictionary<Type, SingleTypeNamedObjectContainer> subcontainersByRegisteredType =
                new Dictionary<Type, SingleTypeNamedObjectContainer>();

            public SingleTypeNamedObjectContainer<TNamedObject> RegisterNamedObjectType<TNamedObject>()
                where TNamedObject : NamedObject
            {
                return RegisterSubcontainer(new SingleTypeNamedObjectContainer<TNamedObject>());
            }

            public TSubcontainer RegisterSubcontainer<TSubcontainer>(TSubcontainer subcontainer)
                where TSubcontainer : SingleTypeNamedObjectContainer
            {
                subcontainersByNamedObjectType.Add(subcontainer.NamedObjectType, subcontainer);
                subcontainersByRegisteredType.Add(typeof(TSubcontainer), subcontainer);
                return subcontainer;
            }

            internal void Register<TNamedObject, TComponent>()
                where TNamedObject : NamedObject
                where TComponent : NamedObjectComponent<TNamedObject>, new()
            {
                GetSubcontainerFor<TNamedObject>().Register<TComponent>();
            }

            public SingleTypeNamedObjectContainer<TNamedObject> GetSubcontainerFor<TNamedObject>()
                where TNamedObject : NamedObject
            {
                return (SingleTypeNamedObjectContainer<TNamedObject>)GetSubcontainerFor(typeof(TNamedObject));
            }

            public SingleTypeNamedObjectContainer GetSubcontainerFor(Type baseNamedObjectType)
            {
                return subcontainersByNamedObjectType[baseNamedObjectType];
            }
        }

        static void Main(string[] args)
        {
            var contaner = new NamedObjectContainer();
            contaner.RegisterNamedObjectType<FooNamedObject>();
            contaner.Register<FooNamedObject, FooNamedObjectComponent>();
        }       
    }

If you run this code with target netcoreapp3.1 - it works.
But if you run with target netcoreapp5.0 - exception throws.

Configuration

Dotnet sdk 5.0.100
OS: MacOS Catalina (x64), Windows 10 1903 (x64)

Regression?

Yes, works on 3.1.

Author: GureevLeonid
Assignees: -
Labels: `area-System.Security`, `untriaged`
Milestone: -

Hmm, VerificationException, if I understand correctly, means that something or unverifiable at runtime. @janvorli might you know best how to proceed here?

Let me run the repro locally and see where the exception stems from in the native runtime.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

omariom picture omariom  路  3Comments

Timovzl picture Timovzl  路  3Comments

matty-hall picture matty-hall  路  3Comments

jamesqo picture jamesqo  路  3Comments

btecu picture btecu  路  3Comments