https://bugs.winehq.org/show_bug.cgi?id=39147
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Component|-unknown |winmm&mci Summary|Reaper 5.0 (x64) crashes at |Reaper 5.0 (x64) crashes at |start when WaveOut is |start when WaveOut is |selected as the audio |selected as the audio |device |device | |(winmm.waveInAddBuffer | |needs stricter header flags | |validation)
--- Comment #10 from Anastasius Focht focht@gmx.net --- Hello folks,
I've spent some hours on this and came to conclusion this is an application bug. It most likely just works on native by chance due to stricter parameter validation.
Thread 0x2c (main):
--- snip --- $ pwd /home/focht/wineprefix64/drive_c/Program Files/REAPER (x64)
$ WINEDEBUG=+tid,+seh,+relay,+winmm,+dsound wine ./reaper.exe >>log.txt 2>&1 ... 002c:Ret winmm.waveInOpen() retval=00000000 ret=14002c583 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e15770 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e157a0 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e157a0,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe157a0, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe157a0) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e17750 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e18700 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e18730 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e18730,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe18730, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe18730) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1a6e0 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1a710 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e1a710,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe1a710, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe1a710) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1c6c0 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1c6f0 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e1c6f0,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe1c6f0, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe1c6f0) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1e6a0 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e1e6d0 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e1e6d0,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe1e6d0, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe1e6d0) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e20680 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e206b0 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e206b0,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe206b0, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe206b0) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e22660 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e22690 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e22690,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe22690, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe22690) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e24640 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00e24670 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00e24670,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xe24670, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xe24670) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 ... --- snip ---
The 0x18 byte buffer allocation preceding each 'winmm.waveInPrepareHeader()' call is an app internal data structure which contains pointers to corresponding WAVEHDR along with other state data. The second one is the WAVEHDR plus the actual buffer in one chunk.
Thread 0x34 (app audio thread):
--- snip --- ... 0034:Call winmm.waveInStart(0000bf00) ret=14002ad08 0034:trace:winmm:waveInStart (0xbf00) 0034:trace:winmm:WINMM_BeginPlaying (0xbf00) 0034:Ret winmm.waveInStart() retval=00000000 ret=14002ad08 0034:Call winmm.waveInAddBuffer(0000bf00,00e15770,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe15770, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000000 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e18700,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe18700, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000000 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e1a6e0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe1a6e0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000000 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e1c6c0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe1c6c0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e1e6a0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe1e6a0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e20680,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe20680, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000000 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e22660,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe22660, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00e24640,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xe24640, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:trace:seh:raise_exception code=c0000005 flags=0 addr=0x14002ac4f ip=14002ac4f tid=0034 0034:trace:seh:raise_exception info[0]=0000000000000000 0034:trace:seh:raise_exception info[1]=0000000000000018 0034:trace:seh:raise_exception rax=0000000000000000 rbx=0000000000e464a0 rcx=0000000000000000 rdx=0000000000e15770 0034:trace:seh:raise_exception rsi=0000000000e155b8 rdi=0000000000e15470 rbp=0000000000e37500 rsp=0000000004e7e400 0034:trace:seh:raise_exception r8=0000000000000009 r9=000000014002ad4f r10=0000000000000000 r11=0000000000000000 0034:trace:seh:raise_exception r12=0000000000e37580 r13=0000000000001000 r14=0000000000000000 r15=0000000000000010 --- snip ---
The app passes by mistake not the actual pointers to the WAVEHDR structures that ought to be prepared earlier but pointers to internal data items. Not all members of the internal data structure are initialized after heap allocation.
Due to Wine not fully validating WAVEHDR flags some 'winmm.waveInAddBuffer()' calls actually succeed (WHDR_PREPARED incorrectly "inherited" from prior heap usage) which messes up the internal buffer counting/state machine.
I added a validation of supported flags (WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP|WHDR_INQUEUE) to 'winmm.waveInAddBuffer()', returning MMSYSERR_INVALPARAM in error case. It prevents the crash.
New output:
--- snip --- ... 002c:Ret winmm.waveInOpen() retval=00000000 ret=14002c583 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00000018) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00fff460 ret=1406c7487 002c:Call ntdll.RtlAllocateHeap(00350000,00000000,00001fa0) ret=1406c7487 002c:Ret ntdll.RtlAllocateHeap() retval=00fff490 ret=1406c7487 002c:Call winmm.waveInPrepareHeader(0000bf00,00fff490,00000030) ret=14002c6d7 002c:trace:winmm:waveInPrepareHeader (0xbf00, 0xfff490, 48) 002c:trace:winmm:WINMM_PrepareHeader (0xbf00, 0xfff490) 002c:Ret winmm.waveInPrepareHeader() retval=00000000 ret=14002c6d7 ... 0034:Call winmm.waveInStart(0000bf00) ret=14002ad08 0034:trace:winmm:waveInStart (0xbf00) 0034:trace:winmm:WINMM_BeginPlaying (0xbf00) 0034:Ret winmm.waveInStart() retval=00000000 ret=14002ad08 0034:Call winmm.waveInAddBuffer(0000bf00,00fff460,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xfff460, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,010023f0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x10023f0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,010043d0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x10043d0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,010063b0,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x10063b0, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,01008390,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x1008390, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,0100a370,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x100a370, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,0100c350,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x100c350, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000022 ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,0100e330,00000030) ret=14002ad4f 0034:trace:winmm:waveInAddBuffer (0xbf00, 0x100e330, 48) 0034:Ret winmm.waveInAddBuffer() retval=0000000b ret=14002ad4f 0034:Call winmm.waveInAddBuffer(0000bf00,00fff490,00000030) ret=14002acbf 0034:trace:winmm:waveInAddBuffer (0xbf00, 0xfff490, 48) 0034:Ret winmm.waveInAddBuffer() retval=00000000 ret=14002acbf 0034:Call KERNEL32.Sleep(00000001) ret=14002b433 ... --- snip ---
Not completely fool-proof since a seemingly valid flags pattern in a garbage WAVEHDR could still appear by chance but it helps the app here.
$ sha1sum reaper50_x64-install.exe d182c3143aed5ff97c963300cbba3c694b84859a reaper50_x64-install.exe
$ wine --version wine-2.0-rc3
Regards