Skip to content
This repository has been archived by the owner on Mar 17, 2024. It is now read-only.

SafeSendMessage BUG!! #1230

Open
AlphaCharry opened this issue Dec 26, 2023 · 4 comments
Open

SafeSendMessage BUG!! #1230

AlphaCharry opened this issue Dec 26, 2023 · 4 comments
Labels

Comments

@AlphaCharry
Copy link

Quasar version

1.4.0

Server installed .NET version

.NET 4.5.2

Server operating system

Windows 10/Server 2019/2016

Client installed .NET version

.NET 4.5.2

Client operating system

Windows 11/Server 2022

Build configuration

Debug

Describe the bug

Quasar.exe Framework V: v4.0.30319 Bug:
"The process terminated due to an unhandled exception. Exception information:".
System.ObjectDisposedException
System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean ByRef) System.StubHelpers.StubHelpers.SafeHandleAddRef(System.Runtime.InteropServices.SafeHandle, Boolean ByRef) Microsoft.Win32.Win32Native.ReleaseMutex(Microsoft.Win32.SafeHandles.SafeWaitHandle) System.Threading.Mutex.ReleaseMutex()
Quasar.Server.Networking.Client.SafeSendMessage(Quasar.Common.Messages.IMessage) Quasar.Server.Networking.Client.ProcessSendBuffers(System.Object) System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() System.Threading.ThreadPoolWorkQueue.Dispatch()

How to reproduce

private void SafeSendMessage(IMessage message)
 {
     try
     {
         _singleWriteMutex.WaitOne();
         using (PayloadWriter pw = new PayloadWriter(_stream, true))
         {
             OnClientWrite(message, pw.WriteMessage(message));
         }
     }
     catch (Exception)
     {
         Disconnect();
         SendCleanup(true);
     }
     finally
     {
         _singleWriteMutex.ReleaseMutex();
     }
 }

C# Code

Open multiple remote control Shell, and when the client may be unstable, the client will return data, and an accident occurs at this time.

Expected behavior

private void SafeSendMessage(IMessage message)
{
if (_stream == null || !_stream.CanWrite)
{
return;
}

try
{
    _singleWriteMutex.WaitOne();
    using (PayloadWriter pw = new PayloadWriter(_stream, true))
    {
        OnClientWrite(message, pw.WriteMessage(message));
    }
}
catch (ObjectDisposedException)
{
    // Handle or log the exception as needed
}
finally
{
    if (_singleWriteMutex != null && _singleWriteMutex.WaitOne(0))
    {
        _singleWriteMutex.ReleaseMutex();
    }
}

}

Actual behavior

"It crashes directly, check the error in the Windows log

Additional context

private void SafeSendMessage(IMessage message)
{
if (_stream == null || !_stream.CanWrite)
{
return;
}

try
{
    _singleWriteMutex.WaitOne();
    using (PayloadWriter pw = new PayloadWriter(_stream, true))
    {
        OnClientWrite(message, pw.WriteMessage(message));
    }
}
catch (ObjectDisposedException)
{
    // Handle or log the exception as needed
}
finally
{
    if (_singleWriteMutex != null && _singleWriteMutex.WaitOne(0))
    {
        _singleWriteMutex.ReleaseMutex();
    }
}

}
this ismy code fix

@AlphaCharry
Copy link
Author

This exception is System.ObjectDisposedException, which usually occurs when trying to access an object that has already been disposed. In this case, the exception occurs in the System.Threading.Mutex.ReleaseMutex() method, which means you may be trying to release a mutex that has already been released. In the code you provided, _singleWriteMutex.ReleaseMutex() is called in the finally block, which means it will be executed whether or not the code in the try block throws an exception. If _singleWriteMutex is released before the finally block is executed, then when the finally block tries to release it, it will throw an ObjectDisposedException. To solve this problem, you need to ensure that _singleWriteMutex is not released before the finally block is executed. You can do this by checking if _singleWriteMutex is null or has already been released. Here is a possible solution:

try
 {
     _singleWriteMutex.WaitOne();
     using (PayloadWriter pw = new PayloadWriter(_stream, true))
     {
         OnClientWrite(message, pw.WriteMessage(message));
     }
 }
 catch (Exception)
 {
     Disconnect();
     SendCleanup(true);
 }
 finally
 {
     if (_singleWriteMutex != null && _singleWriteMutex.SafeWaitHandle.IsClosed == false)
     {
         _singleWriteMutex.ReleaseMutex();
     }
 }

@MaxXor
Copy link
Contributor

MaxXor commented Dec 26, 2023

Can you create a PR with the fix?

@AlphaCharry
Copy link
Author

您可以使用修复程序创建 PR 吗?

What's PR?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants