[PATCH v2] winealsa.drv: Don't crash when getting NULL event from midi
Andrew Eikum
aeikum at codeweavers.com
Thu Nov 29 07:55:22 CST 2018
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
On Tue, Nov 20, 2018 at 09:09:27PM +0100, Fabian Maurer wrote:
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46170
> Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
> ---
> dlls/winealsa.drv/midi.c | 226 ++++++++++++++++++++-------------------
> 1 file changed, 118 insertions(+), 108 deletions(-)
>
> diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
> index 3d4d933ead..58b10bf666 100644
> --- a/dlls/winealsa.drv/midi.c
> +++ b/dlls/winealsa.drv/midi.c
> @@ -292,6 +292,116 @@ static int midiCloseSeq(void)
> return 0;
> }
>
> +static void handle_midi_event(snd_seq_event_t *ev)
> +{
> + WORD wDevID;
> +
> + /* Find the target device */
> + for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
> + if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
> + break;
> + if ((wDevID == MIDM_NumDevs) || (MidiInDev[wDevID].state != 1))
> + FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
> + else {
> + DWORD dwTime, toSend = 0;
> + int value = 0;
> + /* FIXME: Should use ev->time instead for better accuracy */
> + dwTime = GetTickCount() - MidiInDev[wDevID].startTime;
> + TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
> + switch(ev->type)
> + {
> + case SND_SEQ_EVENT_NOTEOFF:
> + toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_NOTEON:
> + toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_KEYPRESS:
> + toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_CONTROLLER:
> + toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_PITCHBEND:
> + value = ev->data.control.value + 0x2000;
> + toSend = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_PGMCHANGE:
> + toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_CHANPRESS:
> + toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
> + break;
> + case SND_SEQ_EVENT_CLOCK:
> + toSend = 0xF8;
> + break;
> + case SND_SEQ_EVENT_START:
> + toSend = 0xFA;
> + break;
> + case SND_SEQ_EVENT_CONTINUE:
> + toSend = 0xFB;
> + break;
> + case SND_SEQ_EVENT_STOP:
> + toSend = 0xFC;
> + break;
> + case SND_SEQ_EVENT_SONGPOS:
> + toSend = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS;
> + break;
> + case SND_SEQ_EVENT_SONGSEL:
> + toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT;
> + break;
> + case SND_SEQ_EVENT_RESET:
> + toSend = 0xFF;
> + break;
> + case SND_SEQ_EVENT_QFRAME:
> + toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER;
> + break;
> + case SND_SEQ_EVENT_SYSEX:
> + {
> + int pos = 0;
> + int len = ev->data.ext.len;
> + LPBYTE ptr = ev->data.ext.ptr;
> + LPMIDIHDR lpMidiHdr;
> +
> + EnterCriticalSection(&crit_sect);
> + while (len) {
> + if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
> + int copylen = min(len, lpMidiHdr->dwBufferLength - lpMidiHdr->dwBytesRecorded);
> + memcpy(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded, ptr + pos, copylen);
> + lpMidiHdr->dwBytesRecorded += copylen;
> + len -= copylen;
> + pos += copylen;
> + /* We check if we reach the end of buffer or the end of sysex before notifying
> + * to handle the case where ALSA split the sysex into several events */
> + if ((lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) ||
> + (*(BYTE*)(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded - 1) == 0xF7)) {
> + MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
> + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
> + lpMidiHdr->dwFlags |= MHDR_DONE;
> + MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
> + }
> + } else {
> + FIXME("Sysex data received but no buffer to store it!\n");
> + break;
> + }
> + }
> + LeaveCriticalSection(&crit_sect);
> + }
> + break;
> + case SND_SEQ_EVENT_SENSING:
> + /* Noting to do */
> + break;
> + default:
> + FIXME("Unhandled event received, type = %x\n", ev->type);
> + break;
> + }
> + if (toSend != 0) {
> + TRACE("Received event %08x from %d:%d\n", toSend, ev->source.client, ev->source.port);
> + MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime);
> + }
> + }
> +}
> +
> static DWORD WINAPI midRecThread(LPVOID arg)
> {
> int npfd;
> @@ -323,116 +433,16 @@ static DWORD WINAPI midRecThread(LPVOID arg)
> }*/
>
> do {
> - WORD wDevID;
> - snd_seq_event_t* ev;
> + snd_seq_event_t *ev;
> +
> EnterCriticalSection(&midiSeqLock);
> - snd_seq_event_input(midiSeq, &ev);
> + snd_seq_event_input(midiSeq, &ev);
> LeaveCriticalSection(&midiSeqLock);
> - /* Find the target device */
> - for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
> - if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
> - break;
> - if ((wDevID == MIDM_NumDevs) || (MidiInDev[wDevID].state != 1))
> - FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
> - else {
> - DWORD dwTime, toSend = 0;
> - int value = 0;
> - /* FIXME: Should use ev->time instead for better accuracy */
> - dwTime = GetTickCount() - MidiInDev[wDevID].startTime;
> - TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
> - switch(ev->type)
> - {
> - case SND_SEQ_EVENT_NOTEOFF:
> - toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_NOTEON:
> - toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_KEYPRESS:
> - toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_CONTROLLER:
> - toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_PITCHBEND:
> - value = ev->data.control.value + 0x2000;
> - toSend = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_PGMCHANGE:
> - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_CHANPRESS:
> - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
> - break;
> - case SND_SEQ_EVENT_CLOCK:
> - toSend = 0xF8;
> - break;
> - case SND_SEQ_EVENT_START:
> - toSend = 0xFA;
> - break;
> - case SND_SEQ_EVENT_CONTINUE:
> - toSend = 0xFB;
> - break;
> - case SND_SEQ_EVENT_STOP:
> - toSend = 0xFC;
> - break;
> - case SND_SEQ_EVENT_SONGPOS:
> - toSend = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS;
> - break;
> - case SND_SEQ_EVENT_SONGSEL:
> - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT;
> - break;
> - case SND_SEQ_EVENT_RESET:
> - toSend = 0xFF;
> - break;
> - case SND_SEQ_EVENT_QFRAME:
> - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER;
> - break;
> - case SND_SEQ_EVENT_SYSEX:
> - {
> - int pos = 0;
> - int len = ev->data.ext.len;
> - LPBYTE ptr = ev->data.ext.ptr;
> - LPMIDIHDR lpMidiHdr;
> -
> - EnterCriticalSection(&crit_sect);
> - while (len) {
> - if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
> - int copylen = min(len, lpMidiHdr->dwBufferLength - lpMidiHdr->dwBytesRecorded);
> - memcpy(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded, ptr + pos, copylen);
> - lpMidiHdr->dwBytesRecorded += copylen;
> - len -= copylen;
> - pos += copylen;
> - /* We check if we reach the end of buffer or the end of sysex before notifying
> - * to handle the case where ALSA split the sysex into several events */
> - if ((lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) ||
> - (*(BYTE*)(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded - 1) == 0xF7)) {
> - MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
> - lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
> - lpMidiHdr->dwFlags |= MHDR_DONE;
> - MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
> - }
> - } else {
> - FIXME("Sysex data received but no buffer to store it!\n");
> - break;
> - }
> - }
> - LeaveCriticalSection(&crit_sect);
> - }
> - break;
> - case SND_SEQ_EVENT_SENSING:
> - /* Noting to do */
> - break;
> - default:
> - FIXME("Unhandled event received, type = %x\n", ev->type);
> - break;
> - }
> - if (toSend != 0) {
> - TRACE("Received event %08x from %d:%d\n", toSend, ev->source.client, ev->source.port);
> - MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime);
> - }
> - }
> - snd_seq_free_event(ev);
> +
> + if (ev) {
> + handle_midi_event(ev);
> + snd_seq_free_event(ev);
> + }
>
> EnterCriticalSection(&midiSeqLock);
> ret = snd_seq_event_input_pending(midiSeq, 0);
> --
> 2.19.1
>
>
>
More information about the wine-devel
mailing list