http://bugs.winehq.org/show_bug.cgi?id=10503
--- Comment #9 from Anastasius Focht focht@gmx.net 2007-11-19 17:31:59 --- Hello again,
well I thought about this problem further. Although an alternate stack for the raise frame would let the vectored X11DRV_DIB_FaultHandler execute successfully to handle the DIB reads/writes, wine wouldn't be able to recover later. When returning from raise handler, wine needs to restore faulting threads full register set from saved context.
The typical sequence goes as follows (excerpt from __wine_call_from_32_restore_regs):
--- snip --- .. push dword ptr [ecx+0C8h] ; CONTEXTOFFSET(SegSs) pop ss mov esp, [ecx+0C4h] ; CONTEXTOFFSET(Esp) push dword ptr [ecx+0C0h] ; CONTEXTOFFSET(EFlags) *boom* push dword ptr [ecx+0BCh] ; CONTEXTOFFSET(SegCs) push dword ptr [ecx+0B8h] ; CONTEXTOFFSET(Eip) push dword ptr [ecx+98h] ; CONTEXTOFFSET(SegDs) mov ecx, [ecx+0ACh] ; CONTEXTOFFSET(Ecx) pop ds iret --- snip ---
Well, as soon as the abused ESP is reloaded from faulting thread context any further restore will fail (likely causing another access violation). I'm not aware of a wine-compatible method (user mode only code) to emulate iret *and* swap stacks.
Interestingly this piece of game code was produced by Microsoft Visual C++ 5.0 compiler ... Who else could produce such brain damaged code ... ok, I've seen several gcc brain damage as well ;-)
There are 24 occurrences of this abusive (DIB) code. Whatever optimization was done ... the compiler simply ran out 8 GP registers and resorted to use ESP/EBP in favor of stack vars - leaving wine's DIB handling mechanism in distress.
I would vote for WONTFIX (until someone decides to change the way DIBs are handled) ;-)
Regards