core: Fix race when deleting channel manager

This PR fixes a possible crash when the channel manager was freed and
there were pending messages in the message queue.
The problem was that even though the message queue already received the
WMQ_QUIT message, it was still possible to enqueue messages after this
point. This resulted in unprocessed messages in the queue when it was
deleted. The delete handler then called into channel handlers which
where aleady freed/deleted.
With this PR adding messages after WMQ_QUIT was posted to the message
queue returns an error and all channel messages are now processed before
the channels are closed/terminated.
This commit is contained in:
Martin Fleisz 2020-11-03 15:24:30 +01:00 committed by akallabeth
parent 81e79a8bac
commit b5fa928311
3 changed files with 11 additions and 1 deletions

View File

@ -730,6 +730,10 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
CHANNEL_OPEN_DATA* pChannelOpenData;
CHANNEL_CLIENT_DATA* pChannelClientData;
MessageQueue_PostQuit(channels->queue, 0);
freerdp_channels_check_fds(channels, instance);
/* tell all libraries we are shutting down */
for (index = 0; index < channels->clientDataCount; index++)
{
@ -749,7 +753,6 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
}
channels->clientDataCount = 0;
MessageQueue_PostQuit(channels->queue, 0);
for (index = 0; index < channels->openDataCount; index++)
{

View File

@ -477,6 +477,7 @@ extern "C"
int tail;
int size;
int capacity;
BOOL closed;
wMessage* array;
CRITICAL_SECTION lock;
HANDLE event;

View File

@ -75,6 +75,9 @@ BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message)
EnterCriticalSection(&queue->lock);
if (queue->closed)
goto out;
if (queue->size == queue->capacity)
{
int old_capacity;
@ -110,6 +113,9 @@ BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message)
if (queue->size > 0)
SetEvent(queue->event);
if (message->id == WMQ_QUIT)
queue->closed = TRUE;
ret = TRUE;
out:
LeaveCriticalSection(&queue->lock);