[PATCH v2] winealsa.drv: Don't crash when getting NULL event from midi

Fabian Maurer dark.shadow4 at web.de
Tue Nov 20 14:09:27 CST 2018


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