[PATCH V2 2/3] mmsystem.dll16: Refcount midihdr to work around buggy application which unprepares buffer during a callback.

Vijay Kiran Kamuju infyquest at gmail.com
Wed Apr 17 08:33:26 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40024
From: Michael Müller <michael at fds-team.de>
Signed-off-by: Vijay Kiran Kamuju <infyquest at gmail.com>
---
 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




More information about the wine-devel mailing list