Lachee / discord-rpc-csharp

C# custom implementation for Discord Rich Presence. Not deprecated and still available!
MIT License
579 stars 96 forks source link

crashes #33

Closed Gl0 closed 5 years ago

Gl0 commented 6 years ago

Added discord-rpc-csharp to our project, some users get following errors:

Either the IAsyncResult object did not come from the corresponding async method on this type, or EndRead was called multiple times with the same IAsyncResult.
   at System.IO.Stream.EndRead(IAsyncResult asyncResult)
   at System.IO.Pipes.PipeStream.EndRead(IAsyncResult asyncResult)
   at DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   at System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
mscorlib
System.ArgumentException: Either the IAsyncResult object did not come from the corresponding async method on this type, or EndRead was called multiple times with the same IAsyncResult.
   at System.IO.Stream.EndRead(IAsyncResult asyncResult)
   at System.IO.Pipes.PipeStream.EndRead(IAsyncResult asyncResult)
   at DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   at System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
System.Collections.ListDictionaryInternal

Int32 EndRead(System.IAsyncResult)

and

Arithmetic operation resulted in an overflow.
   at DiscordRPC.IO.PipeFrame.ReadStream(Stream stream)
   at DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   at System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
Discord RPC
System.OverflowException: Arithmetic operation resulted in an overflow.
   at DiscordRPC.IO.PipeFrame.ReadStream(Stream stream)
   at DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   at System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
System.Collections.ListDictionaryInternal

Boolean ReadStream(System.IO.Stream)

Not sure what they do to get it...

Lachee commented 6 years ago

The second issue seems to have been related to how I was parsing the data from the sockets. It is possible if you get incredibly large amounts of data it could overflow. I have fixed that in the commit I just made. This is a sign of a greater issue however. (turns out the data being received was signed integer and not unsigned)

After some quick research, it seems like the first issue maybe related to the version of C#. Are you using .NET Core or .NET 4.6? It should work either way, but it will help narrow down the problem.

Gl0 commented 6 years ago

.net 4.7

Gl0 commented 6 years ago

looking at commits and not sure, is it time to push updated dll to users, or you have some other ideas for fixes?

Lachee commented 6 years ago

Yeha sorry, not really sure what could be potentially going wrong. Make sure you are only launching the client once and you are running latest version I suppose.

Gl0 commented 6 years ago

I can't be sure about anything, there are like 20k users all over the world, they can do what they want.=)

Gl0 commented 6 years ago

both errors seems gone. received some other errors, not sure how they got it, 1-2 occurrences in 12h and 5k users updated to latest version

Index was outside the bounds of the array.
   at System.Array.Clear(Array array, Int32 index, Int32 length)
   at System.Collections.Generic.Queue`1.Clear()
   at DiscordRPC.RPC.RpcConnection.Shutdown()
   at DiscordRPC.RPC.RpcConnection.Close()
   at DiscordRPC.DiscordRpcClient.Dispose()
   at Tera.RichPresence.RichPresence.Deinitialize()

sorry for non-english logs, but that errors are too rare and we haven't received them from users with en locale

System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı.
   konum: DiscordRPC.IO.ManagedNamedPipeClient.get_IsConnected()
   konum: DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   konum: System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   konum: System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
System.Collections.ListDictionaryInternal

Boolean get_IsConnected()
System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
   в DiscordRPC.IO.ManagedNamedPipeClient.BeginRead()
   в DiscordRPC.IO.ManagedNamedPipeClient.EndRead(IAsyncResult callback)
   в System.IO.Pipes.PipeStream.AsyncPSCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOverlapped)
   в System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
System.Collections.ListDictionaryInternal
Lachee commented 6 years ago

Cheers, I'll look into it when j can. Sorry for the issues with the library but this is the first real big test of the library that I havnt been able to reproduce myself.

Lachee commented 6 years ago

I have fixed a collection of small issues and added better logging. If you are able to reproduce this issue and return the logs that would be awesome.

However, after some research, I doubt you will be able to reproduce the error. It looks like I have a race condition between disposing threads and IO being received back from them. I have failed to account for the fact that the IO will return its value in a new thread in some situations. This requires a bit of a rework but is possible and I shall fix it as soon as I can. I will keep this issue open in the meantime.

As a side note, I recommended just getting the latest I have (once again) as it fixes a handful of related issues which will always be a improvement. In the meantime this bug should happen only fairly rarely (as you said, 3 users or so in 12k total) because it is a race condition when the RichPresence is being disposed or disconnected by discord, 2 unlikely situations to occur mid way through a game. I will work on a fix and get back to you when I can.

Thank you for using my library in such a large project :)

Gl0 commented 6 years ago

Not 12k users, 12hours.=) 24h and 6k users for now, not all of them use discord, 2 more errors logged (same as already mentioned). Will add remote log for DiscordRPC.Logger in next release, so we would see not only things that crashed, but all DiscordRPC Error messages too.

Gl0 commented 6 years ago

Seems it was bad idea... log is flooded with Failed connection to {0}. {1}

Lachee commented 6 years ago

That latest commit fixes the race condition that was in the codebase. Your logging suggests that it cannot connect to the Discord client. The library will continue to attempt time after time to connect to the Discord Client. At the moment it is up to the user of the library to listen for the failure to connect method with client.OnConnectionFailed. I am looking into adding functionality to automatically stop searching once the pipe fails to connect, or at least fixing the delay increment so it gradually becomes longer and longer before the next attempt.

Gl0 commented 6 years ago

Continue attempts is good, just they shouldn't be logged as error. Or may be add Fatal level logging for errors that are not as frequent as failed to connect, and shouldn't appear in normal life.

Gl0 commented 6 years ago

some things received: A exception has occured while trying to parse the pipe data: Arithmetic operation resulted in an overflow. Pipe failed to read from the data received by the stream.

Gl0 commented 6 years ago
   at System.Enum.EnumResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument)
   at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
   at System.Enum.Parse(Type enumType, String value, Boolean ignoreCase)
   at DiscordRPC.Converters.EnumSnakeCaseConverter.TryParseEnum(Type enumType, String str)
   at DiscordRPC.Converters.EnumSnakeCaseConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at DiscordRPC.IO.PipeFrame.GetObject[T]()
   at DiscordRPC.RPC.RpcConnection.MainLoop()
neowutran commented 6 years ago

For this error https://github.com/Lachee/discord-rpc-csharp/issues/33#issuecomment-408158604 The ppl who had this error is turkish ( computer language set to turkish ).
When he switched his computer to english -> no more error

Gl0 commented 6 years ago

seems thing that failed to parse was Requested value 'SetActİvİty' was not found.

Gl0 commented 6 years ago

https://github.com/Lachee/discord-rpc-csharp/issues/33#issuecomment-408041734 seems happens pretty often. Not sure if I should just exclude these errors from log like failed to connect ones, or not.

Lachee commented 6 years ago

Alrighty, I removed the byte swapping from the read I was doing. It seems like you have had someone using a Big Endian machine, which is quiet strange. Should be fixed.

Gl0 commented 6 years ago

Pushed update to users, new reports: (not sure in which order these events happened)

14.08.2018 19:30:45 Pipe failed to read from the data received by the stream.
14.08.2018 19:30:49 Pipe failed to read from the data received by the stream.
14.08.2018 19:30:49 The operation was canceled.
14.08.2018 19:30:49 Unhandled Exception: {0}
14.08.2018 19:30:50    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.Pipes.PipeStream.WinIOError(Int32 errorCode)
   at System.IO.Pipes.PipeStream.EndWrite(IAsyncResult asyncResult)
   at System.IO.Pipes.PipeStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.Pipes.PipeStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at DiscordRPC.IO.PipeFrame.WriteStream(Stream stream)
   at DiscordRPC.IO.ManagedNamedPipeClient.WriteFrame(PipeFrame frame)
   at DiscordRPC.RPC.RpcConnection.ProcessCommandQueue()
   at DiscordRPC.RPC.RpcConnection.MainLoop()
14.08.2018 19:36:29    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.Pipes.PipeStream.WinIOError(Int32 errorCode)
   at System.IO.Pipes.PipeStream.EndWrite(IAsyncResult asyncResult)
   at System.IO.Pipes.PipeStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.Pipes.PipeStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at DiscordRPC.IO.PipeFrame.WriteStream(Stream stream)
   at DiscordRPC.IO.ManagedNamedPipeClient.WriteFrame(PipeFrame frame)
   at DiscordRPC.RPC.RpcConnection.ProcessCommandQueue()
   at DiscordRPC.RPC.RpcConnection.MainLoop()
14.08.2018 19:36:29 The operation was canceled.
14.08.2018 19:36:29 Unhandled Exception: {0}
14.08.2018 19:36:29 Pipe failed to read from the data received by the stream.

Also a lot of pure

Pipe failed to read from the data received by the stream.

sometime interleaved like

14.08.2018 16:53:25 Pipe failed to read from the data received by the stream.
14.08.2018 16:53:25 Failed to write frame because the stream is closed
14.08.2018 16:53:32 Pipe failed to read from the data received by the stream.
14.08.2018 16:53:33 Failed to write frame because the stream is closed
14.08.2018 16:53:57 Pipe failed to read from the data received by the stream.
14.08.2018 16:55:06 Pipe failed to read from the data received by the stream.
Lachee commented 5 years ago

A bug using a older version of the library. If a new bug occurs please create a new issue.