-
Notifications
You must be signed in to change notification settings - Fork 477
Closed
Description
@kimbirkelund made a bug report over at the Moq 4 repository that boils down to a problem with how DynamicProxy processes array parameters of custom attributes. Given the following test code:
namespace Castle.DynamicProxy.Tests;
using System;
using NUnit.Framework;
[TestFixture]
public class Tests : BasePEVerifyTestCase
{
[TestCase(typeof(I1))]
[TestCase(typeof(I2))]
[TestCase(typeof(I3))]
[TestCase(typeof(I4))]
[TestCase(typeof(I5))]
[TestCase(typeof(I6))]
[TestCase(typeof(I7))]
[TestCase(typeof(I8))]
public void Can_proxy_type(Type interfaceTypeToProxy)
{
_ = generator.CreateInterfaceProxyWithoutTarget(interfaceTypeToProxy);
}
[NestedInheritedAttributeWithOnePositionalArrayParameter(null)]
public interface I1 { }
[NestedInheritedAttributeWithOnePositionalArrayParameter(new object[0])]
public interface I2 { }
[NestedNonInheritedAttributeWithOnePositionalArrayParameter(null)]
public interface I3 { }
[NestedNonInheritedAttributeWithOnePositionalArrayParameter(new object[0])]
public interface I4 { }
[NonNestedInheritedAttributeWithOnePositionalArrayParameter(null)]
public interface I5 { }
[NonNestedInheritedAttributeWithOnePositionalArrayParameter(new object[0])]
public interface I6 { }
[NonNestedNonInheritedAttributeWithOnePositionalArrayParameter(null)]
public interface I7 { }
[NonNestedNonInheritedAttributeWithOnePositionalArrayParameter(new object[0])]
public interface I8 { }
[AttributeUsage(AttributeTargets.Interface, Inherited = true)]
public sealed class NestedInheritedAttributeWithOnePositionalArrayParameterAttribute : Attribute
{
public NestedInheritedAttributeWithOnePositionalArrayParameterAttribute(object[] arg) { }
}
[AttributeUsage(AttributeTargets.Interface, Inherited = false)]
public sealed class NestedNonInheritedAttributeWithOnePositionalArrayParameterAttribute : Attribute
{
public NestedNonInheritedAttributeWithOnePositionalArrayParameterAttribute(object[] arg) { }
}
}
[AttributeUsage(AttributeTargets.Interface, Inherited = true)]
public sealed class NonNestedInheritedAttributeWithOnePositionalArrayParameterAttribute : Attribute
{
public NonNestedInheritedAttributeWithOnePositionalArrayParameterAttribute(object[] arg) { }
}
[AttributeUsage(AttributeTargets.Interface, Inherited = false)]
public sealed class NonNestedNonInheritedAttributeWithOnePositionalArrayParameterAttribute : Attribute
{
public NonNestedNonInheritedAttributeWithOnePositionalArrayParameterAttribute(object[] arg) { }
}
The test case using I7
fails with:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
AttributeUtil.GetArguments(IList`1 constructorArguments) line 68
AttributeUtil.ReadAttributeValue(CustomAttributeTypedArgument argument) line 85
AttributeUtil.GetArguments(IList`1 constructorArguments, Type[]& constructorArgTypes, Object[]& constructorArgs) line 62
AttributeUtil.CreateInfo(CustomAttributeData attribute) line 35
AttributeUtil.GetNonInheritableAttributes(MemberInfo member)+MoveNext() line 135
NonInheritableAttributesContributor.Generate(ClassEmitter emitter) line 37
BaseInterfaceProxyGenerator.GenerateType(String typeName, INamingScope namingScope) line 136
<>c__DisplayClass13_0.<GetProxyType>b__0(CacheKey cacheKey) line 85
SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) line 68
BaseProxyGenerator.GetProxyType() line 77
DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) line 115
ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) line 1558
ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors) line 835
ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor[] interceptors) line 728
...
That is, the error surfaces only when the following conditions are met:
- The applied custom attribute is a non-nested type.
- The applied custom attribute is a non-inherited one.
- The applied custom attribute's has an array parameter, for which
null
is used as the argument value.
I haven't studied this in more detail yet, but it seems something goes wrong in the "special case for handling arrays in attributes" logic here.