DotNetty icon indicating copy to clipboard operation
DotNetty copied to clipboard

TypeInitializationException: The type initializer for 'TailContext' threw an exception

Open e45240 opened this issue 5 years ago • 1 comments

I use DotNetty in Unity2018, and encounter the following exception

Exception
ArgumentNullException: Value cannot be null.
Parameter name: element
System.Attribute.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type type, System.Boolean inherit) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.Attribute.GetCustomAttribute (System.Reflection.MemberInfo element, System.Type attributeType, System.Boolean inherit) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.Reflection.CustomAttributeExtensions.GetCustomAttribute (System.Reflection.MemberInfo element, System.Type attributeType, System.Boolean inherit) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T] (System.Reflection.MemberInfo element, System.Boolean inherit) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
DotNetty.Transport.Channels.AbstractChannelHandlerContext.IsSkippable (System.Type handlerType, System.String methodName, System.Type[] paramTypes) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.AbstractChannelHandlerContext.CalculateSkipPropagationFlags (System.Type handlerType) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.DefaultChannelPipeline+TailContext..cctor () (at <22a0a3c55c4140ceadffadf96839be25>:0)
Rethrow as TypeInitializationException: The type initializer for 'TailContext' threw an exception.
DotNetty.Transport.Channels.DefaultChannelPipeline..ctor (DotNetty.Transport.Channels.IChannel channel) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.AbstractChannel.NewChannelPipeline () (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.AbstractChannel..ctor (DotNetty.Transport.Channels.IChannel parent) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.AbstractSocketChannel..ctor (DotNetty.Transport.Channels.IChannel parent, System.Net.Sockets.Socket socket) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.AbstractSocketByteChannel..ctor (DotNetty.Transport.Channels.IChannel parent, System.Net.Sockets.Socket socket) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.TcpSocketChannel..ctor (DotNetty.Transport.Channels.IChannel parent, System.Net.Sockets.Socket socket, System.Boolean connected) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.TcpSocketChannel..ctor (DotNetty.Transport.Channels.IChannel parent, System.Net.Sockets.Socket socket) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.TcpSocketChannel..ctor (System.Net.Sockets.Socket socket) (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Channels.Sockets.TcpSocketChannel..ctor () (at <22a0a3c55c4140ceadffadf96839be25>:0)
System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.RuntimeType.CreateInstanceDefaultCtor (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) (at <982b38b882344e069fa104c0b0b4ebb3>:0)
System.Activator.CreateInstance[T] () (at <982b38b882344e069fa104c0b0b4ebb3>:0)
DotNetty.Transport.Bootstrapping.AbstractBootstrap`2+<>c__10`1[TBootstrap,TChannel,T].<Channel>b__10_0 () (at <22a0a3c55c4140ceadffadf96839be25>:0)
DotNetty.Transport.Bootstrapping.AbstractBootstrap`2+<InitAndRegisterAsync>d__27[TBootstrap,TChannel].MoveNext () (at <22a0a3c55c4140ceadffadf96839be25>:0)

I located the exception at DotNetty.Transport.Channels.AbstractChannelHandlerContext and fix it

protected static bool IsSkippable(Type handlerType, string methodName, params Type[] paramTypes)
{
	var newParamTypes = new Type[paramTypes.Length + 1];
	newParamTypes[0] = typeof(IChannelHandlerContext);
	Array.Copy(paramTypes, 0, newParamTypes, 1, paramTypes.Length);
        // may be null
	// return handlerType.GetMethod(methodName, newParamTypes).GetCustomAttribute<SkipAttribute>(false) != null;
        // replace
        return handlerType.GetMethod(methodName, newParamTypes)?.GetCustomAttribute<SkipAttribute>(false) != null;
}

e45240 avatar Jul 10 '19 01:07 e45240

GetMethod should not return null here, maybe it happen when some code not used for your app is stripped, or some code is obfuscated. Add an null check looks safe, but I'm not sure whether the inner logic of DotNetty still work well without them. May be you have turned on something like code strip(or trim ,or obfuscator) in Unity3d, but it's not safe for code use reflection. And as an workaround, you can simplely turn it off, or config your link.xml( or something else) to except DotNetty from the strip list. Not sure what will happen for AOT/IL2CPP mode or CoreRT.


By the way(Another edge case that may never be fixed), seems there is no Api to strictly check explicit implement of an interface and check override for method of class?(See the below code) It's really hard to find a right way to do that, since explicit implement of interface and new slot of virtual methods is available in C#. handlerType.GetInterfaceMap(typeof(IChannelHandler)) is not available in ns1.3.

```csharp //this(explicit interface)>this(new interface)>=this(override base interface)>base public class TestHandler2 : ChannelHandlerAdapter { public override void ChannelActive(IChannelHandlerContext context) { //should use this }
        public new void ChannelInactive(IChannelHandlerContext context)
        {
            //should not use this
        }
    }
    public class TestHandler : ChannelHandlerAdapter, IChannelHandler
    {
        public new void ChannelActive(IChannelHandlerContext context)
        {
            //should not use this
        }

        void IChannelHandler.ChannelActive(IChannelHandlerContext context)
        {
            //should use this
        }

        public override void ChannelInactive(IChannelHandlerContext context)
        {
            //should not use this
        }

        void IChannelHandler.ChannelInactive(IChannelHandlerContext context)
        {
            //should use this
        }
    }
</details>

yyjdelete avatar Jul 10 '19 05:07 yyjdelete