[Bug 39147] Reaper 5.0 (x64) crashes at start when WaveOut is selected as the audio device ( winmm.waveInAddBuffer needs stricter header flags validation)

wine-bugs at winehq.org wine-bugs at winehq.org
Thu Dec 29 09:15:50 CST 2016


https://bugs.winehq.org/show_bug.cgi?id=39147

Anastasius Focht <focht at 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 at 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

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list