From: Vijay Kiran Kamuju Subject: [PATCH V2 2/3] mmsystem.dll16: Refcount midihdr to work around buggy application which unprepares buffer during a callback. Message-Id: <20190417133327.1593-2-infyquest@gmail.com> Date: Wed, 17 Apr 2019 15:33:26 +0200 In-Reply-To: <20190417133327.1593-1-infyquest@gmail.com> References: <20190417133327.1593-1-infyquest@gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40024 From: Michael Müller Signed-off-by: Vijay Kiran Kamuju --- dlls/mmsystem.dll16/message16.c | 73 +++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/dlls/mmsystem.dll16/message16.c b/dlls/mmsystem.dll16/message16.c index 28f20ba0b29..c2ffa0d3ab1 100644 --- a/dlls/mmsystem.dll16/message16.c +++ b/dlls/mmsystem.dll16/message16.c @@ -33,6 +33,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(winmm); +struct mihdrWrap +{ + int ref; + SEGPTR mh16; + MIDIHDR hdr; +}; + /* ================================= * A U X M A P P E R S * ================================= */ @@ -117,13 +124,13 @@ static void MMSYSTDRV_MidiIn_MapCB(UINT uMsg, DWORD_PTR* dwUser, DWORD_PTR* dwPa case MIM_LONGDATA: case MIM_LONGERROR: { - LPMIDIHDR mh32 = (LPMIDIHDR)(*dwParam1); - SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*dwParam1, struct mihdrWrap, hdr); + SEGPTR segmh16 = mh32->mh16; LPMIDIHDR16 mh16 = MapSL(segmh16); *dwParam1 = (DWORD)segmh16; - mh16->dwFlags = mh32->dwFlags; - mh16->dwBytesRecorded = mh32->dwBytesRecorded; + mh16->dwFlags = mh32->hdr.dwFlags; + mh16->dwBytesRecorded = mh32->hdr.dwBytesRecorded; } break; default: @@ -175,17 +182,17 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_Map16To32W (UINT wMsg, DWORD_PTR* lpP break; case MODM_PREPARE: { - LPMIDIHDR mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIHDR) + sizeof(MIDIHDR)); + struct mihdrWrap *mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mihdrWrap)); LPMIDIHDR16 mh16 = MapSL(*lpParam1); if (mh32) { - *(LPMIDIHDR*)mh32 = (LPMIDIHDR)*lpParam1; - mh32 = (LPMIDIHDR)((LPSTR)mh32 + sizeof(LPMIDIHDR)); - mh32->lpData = MapSL((SEGPTR)mh16->lpData); - mh32->dwBufferLength = mh16->dwBufferLength; - mh32->dwBytesRecorded = mh16->dwBytesRecorded; - mh32->dwUser = mh16->dwUser; - mh32->dwFlags = mh16->dwFlags; + mh32->ref = 2; + mh32->mh16 = (SEGPTR)*lpParam1; + mh32->hdr.lpData = MapSL((SEGPTR)mh16->lpData); + mh32->hdr.dwBufferLength = mh16->dwBufferLength; + mh32->hdr.dwBytesRecorded = mh16->dwBytesRecorded; + mh32->hdr.dwUser = mh16->dwUser; + mh32->hdr.dwFlags = mh16->dwFlags; mh16->lpNext = (MIDIHDR16*)mh32; /* for reuse in unprepare and write */ *lpParam1 = (DWORD)mh32; *lpParam2 = offsetof(MIDIHDR,dwOffset); /* old size, without dwOffset */ @@ -200,16 +207,17 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_Map16To32W (UINT wMsg, DWORD_PTR* lpP case MODM_LONGDATA: { LPMIDIHDR16 mh16 = MapSL(*lpParam1); - LPMIDIHDR mh32 = (MIDIHDR*)mh16->lpNext; + struct mihdrWrap *mh32 = (struct mihdrWrap*)mh16->lpNext; - *lpParam1 = (DWORD)mh32; + mh32->ref++; + *lpParam1 = (DWORD)&mh32->hdr; *lpParam2 = offsetof(MIDIHDR,dwOffset); /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == MODM_LONGDATA && mh32->dwBufferLength < mh16->dwBufferLength) { + if (wMsg == MODM_LONGDATA && mh32->hdr.dwBufferLength < mh16->dwBufferLength) { ERR("Size of buffer has been increased from %d to %d, keeping initial value\n", - mh32->dwBufferLength, mh16->dwBufferLength); + mh32->hdr.dwBufferLength, mh16->dwBufferLength); } else - mh32->dwBufferLength = mh16->dwBufferLength; + mh32->hdr.dwBufferLength = mh16->dwBufferLength; ret = MMSYSTEM_MAP_OKMEM; } break; @@ -267,16 +275,27 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_UnMap16To32W(UINT wMsg, DWORD_PTR* lpP case MODM_UNPREPARE: case MODM_LONGDATA: { - LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); - LPMIDIHDR16 mh16 = MapSL(*(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR))); + struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*lpParam1, struct mihdrWrap, hdr); + LPMIDIHDR16 mh16; - assert((MIDIHDR*)mh16->lpNext == mh32); - mh16->dwFlags = mh32->dwFlags; + /* Prosound unprepares the buffer during a callback */ + if (mh32->mh16) + { + mh16 = MapSL(mh32->mh16); + assert((struct mihdrWrap *)mh16->lpNext == mh32); + mh16->dwFlags = mh32->hdr.dwFlags; - if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, (LPSTR)mh32 - sizeof(LPMIDIHDR)); - mh16->lpNext = 0; + if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) + { + mh32->mh16 = 0; + mh32->ref--; + mh16->lpNext = 0; + } } + + if (!--mh32->ref) + HeapFree(GetProcessHeap(), 0, mh32); + ret = MMSYSTEM_MAP_OK; } break; @@ -307,12 +326,12 @@ static void MMSYSTDRV_MidiOut_MapCB(UINT uMsg, DWORD_PTR* dwUser, DWORD_PTR* dwP case MOM_DONE: { /* initial map is: 16 => 32 */ - LPMIDIHDR mh32 = (LPMIDIHDR)(*dwParam1); - SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*dwParam1, struct mihdrWrap, hdr); + SEGPTR segmh16 = mh32->mh16; LPMIDIHDR16 mh16 = MapSL(segmh16); *dwParam1 = (DWORD)segmh16; - mh16->dwFlags = mh32->dwFlags; + mh16->dwFlags = mh32->hdr.dwFlags; } break; default: -- 2.17.0