8074211: javax.sound.midi: Error with send System Exclusive messages of different length

8250667: MIDI sysex over USB scrambled when reply length matches previous message

Reviewed-by: prr
This commit is contained in:
Alec Su 2023-11-21 19:26:49 +00:00 committed by Phil Race
parent 6d824364c2
commit e47cf611c9
5 changed files with 46 additions and 26 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -301,7 +301,7 @@ INT32 prepareBuffers(MidiDeviceHandle* handle) {
}
sysex = (SysExQueue*) handle->longBuffers;
for (i = 0; i<sysex->count; i++) {
MIDIHDR* hdr = &(sysex->header[i]);
MIDIHDR* hdr = &(sysex->headerInfo[i].header);
midiInPrepareHeader((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));
err = midiInAddBuffer((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));
}
@ -320,7 +320,7 @@ INT32 unprepareBuffers(MidiDeviceHandle* handle) {
}
sysex = (SysExQueue*) handle->longBuffers;
for (i = 0; i<sysex->count; i++) {
err = midiInUnprepareHeader((HMIDIIN) handle->deviceHandle, &(sysex->header[i]), sizeof(MIDIHDR));
err = midiInUnprepareHeader((HMIDIIN) handle->deviceHandle, &(sysex->headerInfo[i].header), sizeof(MIDIHDR));
}
MIDIIN_CHECK_ERROR;
return (INT32) err;
@ -502,7 +502,7 @@ void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) {
}
sysex = (SysExQueue*) handle->longBuffers;
if (msg->type == LONG_MESSAGE && sysex) {
MIDIHDR* hdr = &(sysex->header[msg->data.l.index]);
MIDIHDR* hdr = &(sysex->headerInfo[msg->data.l.index].header);
//fprintf(stdout, "ReleaseMessage index %d\n", msg->data.l.index); fflush(stdout);
hdr->dwBytesRecorded = 0;
midiInAddBuffer((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -161,7 +161,7 @@ INT32 unprepareLongBuffers(MidiDeviceHandle* handle) {
}
sysex = (SysExQueue*) handle->longBuffers;
for (i = 0; i<sysex->count; i++) {
MIDIHDR* hdr = &(sysex->header[i]);
MIDIHDR* hdr = &(sysex->headerInfo[i].header);
if (hdr->dwFlags) {
err = midiOutUnprepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
}
@ -170,8 +170,9 @@ INT32 unprepareLongBuffers(MidiDeviceHandle* handle) {
return (INT32) err;
}
INT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData) {
INT32 freeLongBuffer(MidiHeaderInfo* info, HMIDIOUT deviceHandle, INT32 minToLeaveData) {
MMRESULT err = MMSYSERR_NOERROR;
MIDIHDR* hdr = &(info->header);
if (!hdr) {
ERROR0("MIDI_OUT_freeLongBuffer: hdr == NULL\n");
@ -180,10 +181,11 @@ INT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData)
if (hdr->dwFlags && deviceHandle) {
err = midiOutUnprepareHeader(deviceHandle, hdr, sizeof(MIDIHDR));
}
if (hdr->lpData && (((INT32) hdr->dwBufferLength) < minToLeaveData || minToLeaveData < 0)) {
if (hdr->lpData && (info->bufferLength < minToLeaveData || minToLeaveData < 0)) {
free(hdr->lpData);
hdr->lpData=NULL;
hdr->dwBufferLength=0;
info->bufferLength=0;
}
hdr->dwBytesRecorded=0;
hdr->dwFlags=0;
@ -201,7 +203,7 @@ INT32 freeLongBuffers(MidiDeviceHandle* handle) {
}
sysex = (SysExQueue*) handle->longBuffers;
for (i = 0; i<sysex->count; i++) {
err = freeLongBuffer(&(sysex->header[i]), (HMIDIOUT) handle->deviceHandle, -1);
err = freeLongBuffer(&(sysex->headerInfo[i]), (HMIDIOUT) handle->deviceHandle, -1);
}
MIDIOUT_CHECK_ERROR;
return (INT32) err;
@ -352,6 +354,7 @@ INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT
INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) {
MMRESULT err;
SysExQueue* sysex;
MidiHeaderInfo* info = NULL;
MIDIHDR* hdr = NULL;
INT32 remainingSize;
int i;
@ -378,10 +381,12 @@ INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 siz
while (!hdr && handle->platformData) {
/* find a non-queued header */
for (i = 0; i < sysex->count; i++) {
hdr = &(sysex->header[i]);
info = &(sysex->headerInfo[i]);
hdr = &(info->header);
if ((hdr->dwFlags & MHDR_DONE) || (hdr->dwFlags == 0)) {
break;
}
info = NULL;
hdr = NULL;
}
/* wait for a buffer to free up */
@ -404,22 +409,26 @@ INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 siz
}
TRACE2("-> sending %d bytes with buffer index=%d\n", (int) size, (int) hdr->dwUser);
freeLongBuffer(hdr, handle->deviceHandle, (INT32) size);
freeLongBuffer(info, handle->deviceHandle, (INT32) size);
if (hdr->lpData == NULL) {
hdr->lpData = malloc(size);
hdr->dwBufferLength = size;
info->bufferLength = size;
}
// Because midiOutLongMsg() ignores dwBytesRecorded, set both
// dwBufferLength to the size of the data. The actual buffer
// size is recorded in info->bufferLength.
hdr->dwBufferLength = size;
hdr->dwBytesRecorded = size;
memcpy(hdr->lpData, data, size);
err = midiOutPrepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
if (err != MMSYSERR_NOERROR) {
freeLongBuffer(hdr, handle->deviceHandle, -1);
freeLongBuffer(info, handle->deviceHandle, -1);
MIDIOUT_CHECK_ERROR;
return (INT32) err;
}
err = midiOutLongMsg((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
if (err != MMSYSERR_NOERROR) {
freeLongBuffer(hdr, handle->deviceHandle, -1);
freeLongBuffer(info, handle->deviceHandle, -1);
ERROR0("ERROR: MIDI_OUT_SendLongMessage: midiOutLongMsg returned error:\n");
MIDIOUT_CHECK_ERROR;
return (INT32) err;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -89,7 +89,7 @@ int MIDI_WinCreateLongBufferQueue(MidiDeviceHandle* handle, int count, int size,
SysExQueue* sysex;
int i;
UBYTE* dataPtr;
int structSize = sizeof(SysExQueue) + ((count - 1) * sizeof(MIDIHDR));
int structSize = sizeof(SysExQueue) + ((count - 1) * sizeof(MidiHeaderInfo));
sysex = (SysExQueue*) malloc(structSize);
if (!sysex) return FALSE;
@ -112,10 +112,11 @@ int MIDI_WinCreateLongBufferQueue(MidiDeviceHandle* handle, int count, int size,
// set up headers
dataPtr = preAllocatedMem;
for (i=0; i<count; i++) {
sysex->header[i].lpData = dataPtr;
sysex->header[i].dwBufferLength = size;
sysex->headerInfo[i].header.lpData = dataPtr;
sysex->headerInfo[i].header.dwBufferLength = size;
sysex->headerInfo[i].bufferLength = size;
// user data is the index of the buffer
sysex->header[i].dwUser = (DWORD) i;
sysex->headerInfo[i].header.dwUser = (DWORD) i;
dataPtr += size;
}
return TRUE;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,12 +46,17 @@
#include "PlatformMidi.h"
typedef struct tag_MidiHeaderInfo {
MIDIHDR header; // Windows specific structure to hold meta info
INT32 bufferLength; // the actual length of the buffer in MIDIHDR
} MidiHeaderInfo;
typedef struct tag_SysExQueue {
int count; // number of sys ex headers
int size; // data size per sys ex header
int ownsLinearMem; // true when linearMem is to be disposed
UBYTE* linearMem; // where the actual sys ex data is, count*size bytes
MIDIHDR header[1]; // Windows specific structure to hold meta info
int count; // number of sys ex headers
int size; // data size per sys ex header
int ownsLinearMem; // true when linearMem is to be disposed
UBYTE* linearMem; // where the actual sys ex data is, count*size bytes
MidiHeaderInfo headerInfo[1]; // a structure to hold MIDIHDR and the actual buffer length
} SysExQueue;
/* set the startTime field in MidiDeviceHandle */

View File

@ -34,7 +34,7 @@ import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE;
/**
* @test
* @bug 8237495 8301310
* @bug 8074211 8237495 8301310
* @summary fail with memory errors when asked to send a sysex message starting
* with 0xF7
*/
@ -114,6 +114,11 @@ public final class SendRawSysexMessage {
(byte) SPECIAL_SYSTEM_EXCLUSIVE}), -1);
System.err.println("note off");
r.send(new ShortMessage(ShortMessage.NOTE_OFF, 5, 5), -1);
// The three parts of the sysex below are added for
// JDK-8301310, but it can also used to test JDK-8074211.
// However, The testcase does not fail when JDK-8074211 occurs.
// It's recommended to setup a loopback MIDI device then check
// whether the sysex received is the same as the testcase.
System.err.println("sysex part 1 of 3");
r.send(new SysexMessage(new byte[]{
(byte) SYSTEM_EXCLUSIVE, 0x7D, 0x01, 0x02}, 4), -1);