http://bugs.winehq.org/show_bug.cgi?id=10280
Tim tccowper@yahoo.com.au changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |tccowper@yahoo.com.au
--- Comment #34 from Tim tccowper@yahoo.com.au 2010-07-20 04:10:17 --- Apologies in advance if this comment is a bit lengthy. I have investigated further, testing with Oblivion on my machine and can clarify a bit further:
1. While the player is riding a horse with armour, Oblivion plays a number of sound files. One of these, 'data\sound\fx\npc\horse\foot\armor\npc_horse_foot_armor_01.wav', causes the crash.
2. As with the other sound files, the code path runs through mmio.c:
(a) the file is opened for reading via a call to MMIO_Open('data\sound\fx\npc\horse\foot\armor\npc_horse_foot_armor_01.wav', 0x33f11c, 00010000, ansi) - this function is documented at http://msdn.microsoft.com/en-us/library/dd757331%28v=VS.85%29.aspx;
(b) a custom I/O procedure is installed on the fly with a FOURCC code of " WAV" via a call to MMIO_InstallIOProc(00564157, 0x6aaaa0, 00010000, ansi) - see http://msdn.microsoft.com/en-us/library/dd757323%28VS.85%29.aspx;
(c) an internal buffer of 8192 bytes is allocated via a call to MMIO_SetBuffer(0x5c5f420 (nil) 8192 0) - see http://msdn.microsoft.com/en-us/library/dd757338%28VS.85%29.aspx; and
(d) a call is then made to descend into the parent chunk of the file via mmioDescend(0x37, 0x33f0c0, (nil), 0000) - see http://msdn.microsoft.com/en-us/library/dd757318%28VS.85%29.aspx.
3. The actual crash occurs in the mmioDescend function when the code attempts to make the following TRACE call, resulting in a buffer overflow ("wine_dbg_vprintf: debugstr buffer overflow"):
TRACE("ckid=%4.4s fcc=%4.4s cksize=%08X !\n",(LPCSTR)&lpck->ckid, srchType ? (LPCSTR)&lpck->fccType:"<na>",lpck->cksize);
After separating this statement into its individual elements, recompiling and doing another trace, we can be more specific and say that the crash occurs when the attempt is made to cast the FOURCC &lpck->ckid as a string pointer then pass this to TRACE to print, i.e. the following is what calls the crash:
TRACE("ckid=%4.4s\n", (LPCSTR)&lpck->ckid);
At the time this call is made the value of lpck->ckid is 9FFEA1FE.
The FOURCC datatype (http://msdn.microsoft.com/en-us/library/dd375802%28VS.85%29.aspx) consists of 4 bytes, 1 for each character. There is no null-terminating byte, but as Eric points out, this should not be a problem as the %4.4s format specifier in the TRACE call should only print four characters. A minor niggle with this approach is that it does not respect byte order (assumes little endian), but that's not the concern here.
What then is tripping the buffer overflow assertion in wine_dbg_vprintf and causing the crash? I don't know yet. Could there be a bug in the wine_dbg_printf function itself?
In any case, and somewhat oddly, if I include a standard function to convert FOURCC codes into null terminated strings (also respecting byte order), then feed these into the TRACE calls, there is no crash.
I have no idea why, but at least it's a workaround for this bug. I've attached a patch, along with a modified form of mmio.c and the trace it produces, which shows the two approaches running side by side.
Another more simple way to work around this if you don't care about receiving the mmio debug info is to just comment out or delete all the TRACE calls in the mmioDescend function of mmio.c, recompile wine and run Oblivion with that.
Hope this helps someone, and thanks again to the Wine team for their amazing effort in getting complex games like this to run on Linux.