Skip to content

[mono] CustomAttrBuilder does not support RuntimeType arguments #58019

@uweigand

Description

@uweigand

Description

Running the aspnetcore Microsoft.AspNetCore.Server.Kestrel.Core.Tests unit tests on Mono fails with:

    Microsoft.AspNetCore.Server.Kestrel.Core.Tests.HttpConnectionTests.WriteDataRateTimeoutAbortsConnection [FAIL]
      Castle.DynamicProxy.ProxyGenerationException : Due to limitations in CLR, DynamicProxy was unable to successfully replicate non-inheritable attribute System.Runtime.CompilerServices.AsyncStateMachineAttribute on System.IO.Pipelines.PipeReader.ReadAtLeastAsyncCore. To avoid this error you can chose not to replicate this attribute type by calling 'Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(System.Runtime.CompilerServices.AsyncStateMachineAttribute))'.
      ---- System.ArgumentException : Cannot emit a CustomAttribute with argument of type System.RuntimeType.
      Stack Trace:
           at Castle.DynamicProxy.Internal.AttributeUtil.GetNonInheritableAttributes(MemberInfo member)+MoveNext()
           at Castle.DynamicProxy.Contributors.CompositeTypeContributor.ImplementMethod(MetaMethod method, ClassEmitter class, ProxyGenerationOptions options, OverrideMethodDelegate overrideMethod)
           at Castle.DynamicProxy.Contributors.CompositeTypeContributor.Generate(ClassEmitter class, ProxyGenerationOptions options)
           at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType(String name, Type[] interfaces, INamingScope namingScope)
           at Castle.DynamicProxy.Generators.ClassProxyGenerator.<>c__DisplayClass1_0.<GenerateCode>b__0(String n, INamingScope s)
           at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
           at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
           at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
           at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
           at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
           at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments)
           at Moq.Mock`1[[System.IO.Pipelines.PipeReader, System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]].InitializeInstancePexProtected()
           at Moq.PexProtector.Invoke(Action action)
           at Moq.Mock`1[[System.IO.Pipelines.PipeReader, System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]].InitializeInstance()
           at Moq.Mock`1[[System.IO.Pipelines.PipeReader, System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]].OnGetObject()
           at Moq.Mock.get_Object()
           at Moq.Mock`1[[System.IO.Pipelines.PipeReader, System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]].get_Object()
           at Moq.Mock.Of[PipeReader]()
        /home/uweigand/aspnetcore/src/Servers/Kestrel/Core/test/HttpConnectionTests.cs(24,0): at Microsoft.AspNetCore.Server.Kestrel.Core.Tests.HttpConnectionTests.WriteDataRateTimeoutAbortsConnection()
        --- End of stack trace from previous location ---
        ----- Inner Stack Trace -----
        /home/uweigand/runtime/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs(265,0): at System.Reflection.Emit.CustomAttributeBuilder.Initialize(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues)
        /home/uweigand/runtime/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs(112,0): at System.Reflection.Emit.CustomAttributeBuilder..ctor(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues)
           at Castle.DynamicProxy.CustomAttributeInfo..ctor(ConstructorInfo constructor, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues)
           at Castle.DynamicProxy.Internal.AttributeUtil.CreateInfo(CustomAttributeData attribute)

Configuration

.NET 6 Preview7 re-built for the linux-s390x target (using the Mono runtime by default).

Regression?

Probably not.

Other information

This is supported by the CoreCLR runtime, but in the Mono runtime it fails as System.RuntimeType is rejected by this condition in IsValidType (src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs):

            if (t.IsClass && !(t.IsArray || t == typeof(object) || t == typeof(Type) || t == typeof(string) || t.Assembly.GetName().Name == "mscorlib"))
                 return false;

Note that the IsValidParam routine (which gets invoked first) actually has a more generic check which accepts System.RuntimeType:

                if (!t.IsPrimitive && !typeof(Type).IsAssignableFrom(t) && t != typeof(string) && !t.IsEnum)
                    return false;

But this doesn't help since the situation is rejected by IsValidType first. Changing the t == typeof(Type) in IsValidType also to typeof(Type).IsAssignableFrom(t) seems to fix the problem; the test case then passes.

I'll submit a PR shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions