[WDMAUD] Fix race condition bug with USE_MMIXER_LIB defined (#3148)

Remove misuse of multithreading and use NtDeviceIoContol with completion apc
callback instead (mirrors usage of WriteFileEx in WdmAudCommitWaveBufferByLegacy).

This fixes a crash caused by race condition. Code was simulating completion
callback using a thread, this resulted in single threaded code being executed
simultaneously by multiple threads.

CORE-17214
This commit is contained in:
Michael Stamper 2020-09-08 21:59:09 +00:00 committed by Stanislav Motylkov
parent 4aeb45ce0c
commit b8e936a57b
No known key found for this signature in database
GPG key ID: AFE513258CBA9E92

View file

@ -12,19 +12,14 @@
#include <winreg.h> #include <winreg.h>
#include <setupapi.h> #include <setupapi.h>
#include <mmixer.h> #include <mmixer.h>
#define NTOS_MODE_USER
#include <ndk/rtlfuncs.h>
#include <ndk/iofuncs.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
#include <mmebuddy_debug.h> #include <mmebuddy_debug.h>
typedef struct
{
KSSTREAM_HEADER Header;
HANDLE hDevice;
PSOUND_OVERLAPPED Overlap;
LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine;
DWORD IoCtl;
}IO_PACKET, *LPIO_PACKET;
BOOL MMixerLibraryInitialized = FALSE; BOOL MMixerLibraryInitialized = FALSE;
@ -785,27 +780,25 @@ WdmAudGetWavePositionByMMixer(
return MMSYSERR_NOTSUPPORTED; return MMSYSERR_NOTSUPPORTED;
} }
DWORD static
WINAPI VOID WINAPI
IoStreamingThread( CommitWaveBufferApc(PVOID ApcContext,
LPVOID lpParameter) PIO_STATUS_BLOCK IoStatusBlock,
ULONG Reserved)
{ {
DWORD Length; DWORD dwErrorCode;
//MMRESULT Result; PSOUND_OVERLAPPED Overlap;
LPIO_PACKET Packet = (LPIO_PACKET)lpParameter; KSSTREAM_HEADER* lpHeader;
/*Result = */ SyncOverlappedDeviceIoControl(Packet->hDevice, dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status);
Packet->IoCtl, Overlap = (PSOUND_OVERLAPPED)IoStatusBlock;
NULL, lpHeader = Overlap->CompletionContext;
0,
&Packet->Header,
sizeof(KSSTREAM_HEADER),
&Length);
Packet->CompletionRoutine(ERROR_SUCCESS, Packet->Header.DataUsed, (LPOVERLAPPED)Packet->Overlap); /* Call mmebuddy overlap routine */
Overlap->OriginalCompletionRoutine(dwErrorCode,
lpHeader->DataUsed, &Overlap->Standard);
HeapFree(GetProcessHeap(), 0, Packet); HeapFree(GetProcessHeap(), 0, lpHeader);
return 0;
} }
MMRESULT MMRESULT
@ -819,8 +812,9 @@ WdmAudCommitWaveBufferByMMixer(
PSOUND_DEVICE SoundDevice; PSOUND_DEVICE SoundDevice;
MMDEVICE_TYPE DeviceType; MMDEVICE_TYPE DeviceType;
MMRESULT Result; MMRESULT Result;
LPIO_PACKET Packet; ULONG IoCtl;
HANDLE hThread; KSSTREAM_HEADER* lpHeader;
NTSTATUS Status;
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
@ -832,37 +826,44 @@ WdmAudCommitWaveBufferByMMixer(
Result = GetSoundDeviceType(SoundDevice, &DeviceType); Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR ); SND_ASSERT( Result == MMSYSERR_NOERROR );
Packet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IO_PACKET)); lpHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSSTREAM_HEADER));
if ( ! Packet ) if ( ! lpHeader )
{ {
/* no memory */ /* no memory */
return MMSYSERR_NOMEM; return MMSYSERR_NOMEM;
} }
/* setup stream packet */ /* setup stream packet */
Packet->Header.Size = sizeof(KSSTREAM_HEADER); lpHeader->Size = sizeof(KSSTREAM_HEADER);
Packet->Header.PresentationTime.Numerator = 1; lpHeader->PresentationTime.Numerator = 1;
Packet->Header.PresentationTime.Denominator = 1; lpHeader->PresentationTime.Denominator = 1;
Packet->Header.Data = OffsetPtr; lpHeader->Data = OffsetPtr;
Packet->Header.FrameExtent = Length; lpHeader->FrameExtent = Length;
Packet->hDevice = SoundDeviceInstance->Handle; Overlap->CompletionContext = lpHeader;
Packet->Overlap = Overlap; Overlap->OriginalCompletionRoutine = CompletionRoutine;
Packet->CompletionRoutine = CompletionRoutine; IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
Packet->IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
if (DeviceType == WAVE_OUT_DEVICE_TYPE) if (DeviceType == WAVE_OUT_DEVICE_TYPE)
{ {
Packet->Header.DataUsed = Length; lpHeader->DataUsed = Length;
} }
hThread = CreateThread(NULL, 0, IoStreamingThread, (LPVOID)Packet, 0, NULL); Status = NtDeviceIoControlFile(SoundDeviceInstance->Handle,
if (hThread == NULL) NULL,
CommitWaveBufferApc,
NULL,
(PIO_STATUS_BLOCK)Overlap,
IoCtl,
NULL,
0,
lpHeader,
sizeof(KSSTREAM_HEADER));
if (!NT_SUCCESS(Status))
{ {
/* error */ DPRINT1("NtDeviceIoControlFile() failed with status %08lx\n", Status);
return MMSYSERR_ERROR; return MMSYSERR_ERROR;
} }
CloseHandle(hThread);
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
} }