Open LolliDepp opened 5 years ago
Faced similar issue. Though I see a fix already applied for handling a disposed timer here - a4bcac3, using v0.15.2
Catched same exception in v0.15.2.11
me to System.ObjectDisposedException: Cannot access a disposed object. at System.Threading.TimerQueueTimer.Change(UInt32 dueTime, UInt32 period) at System.Threading.Timer.Change(Int32 dueTime, Int32 period) at WebSocket4Net.WebSocket.ClearTimer() at WebSocket4Net.WebSocket.FireClosed() at WebSocket4Net.WebSocket.OnClosed() at SuperSocket.ClientEngine.AuthenticatedStreamTcpSession.SendInternal(PosList`1 items) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.Security._SslStream.StartWriting(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security._SslStream.WriteCallback(IAsyncResult transportResult) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.ContextAwareResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped pOVERLAP)
Can also confirm.
Interlocked.CompareExchange
was changed to lock
statement at 1ab610a. I think this change is not equivalent.
In my case, this bug happens when both client and server close connection. I suppose that two threads may enter that lock
section: my code and data receiving thread. When my code calls Close
first, then ping timer is replaced by closing handshake timer. But at the same time receiving thread may also call ClearTimer
, so both will simultaneously enter lock
. Receiving thread code will check m_WebSocketTimer
that will not be null
, then dispose old local timer copy that have already been disposed by my code.
Same error here as well
Cannot access a disposed object. at System.Threading.TimerQueueTimer.Change(UInt32 dueTime, UInt32 period) at System.Threading.Timer.Change(Int32 dueTime, Int32 period) at WebSocket4Net.WebSocket.ClearTimer() at WebSocket4Net.WebSocket.FireClosed() at WebSocket4Net.WebSocket.OnClosed() at SuperSocket.ClientEngine.AuthenticatedStreamTcpSession.OnDataRead(IAsyncResult result) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.AsyncProtocolRequest.CompleteWithError(Exception e) at System.Net.Security._SslStream.ReadHeaderCallback(AsyncProtocolRequest asyncRequest) at System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result) at System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes) at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.ContextAwareResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped pOVERLAP)
We are hitting this routinely during stress tests.
Could it be caused by the double-checked locking on a non-volatile field used inside ClearTimer()
here:
https://github.com/kerryjiang/WebSocket4Net/blob/v0.15/WebSocket4Net/WebSocket.cs#L710
This seems to have happened seconds after the client handled a disconnect from the server. The client had been running for about 2 hours already
I didn't delve in the source just yet but it looks like this may be solved just by checking if the timer is disposed
Here are the logs:
Cannot access a disposed object. at System.Threading.TimerQueueTimer.Change(UInt32 dueTime, UInt32 period) at WebSocket4Net.WebSocket.ClearTimer() at WebSocket4Net.WebSocket.FireClosed() at WebSocket4Net.WebSocket.OnClosed() at SuperSocket.ClientEngine.ClientSession.OnClosed() at SuperSocket.ClientEngine.AsyncTcpSession.ProcessReceive(SocketAsyncEventArgs e) at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs e) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags) at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped pOVERLAP)