http://bugs.winehq.org/show_bug.cgi?id=30720
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |Installer URL|http://news.bigdownload.com |http://www.fileplanet.com/1 |/2009/02/26/download-the-la |96906/190000/fileinfo/The-L |st-remnant-demo/ |ast-Remnant-Trial-%28North- | |American%29 CC| |focht@gmx.net Component|gdi32 |ntdll Summary|The Last Remnant |The Last Remnant Demo |demo(non-steam): installer |(non-steam) installer |crashes immediately |crashes on startup | |(application bug, heap | |management)
--- Comment #7 from Anastasius Focht focht@gmx.net --- Hello folks,
it's as Alexandre said - the installer contains a stupid bug which just works by chance with Windows (differences in heap management/implementation).
Let me elaborate a bit ... ;-)
Relevant part of trace log:
--- snip --- $ WINEDEBUG=+tid,+seh,+relay,+msi wine ./setup.exe >>log.txt 2>&1 ... 0024:Call KERNEL32.CreateFileA(0048b569 "Z:\home\focht\Downloads\The Last Remnant Trial Version\0x0409.ini",80000000,00000001,00000000,00000003,00000001,00000000) ret=0040d95b 0024:Ret KERNEL32.CreateFileA() retval=00000074 ret=0040d95b 0024:Call KERNEL32.ReadFile(00000074,0033d0a0,00000400,0033d4a0,00000000) ret=00404d5c 0024:Ret KERNEL32.ReadFile() retval=00000001 ret=00404d5c 0024:Call KERNEL32.SetFilePointer(00000074,00000000,00000000,00000000) ret=00404da9 0024:Ret KERNEL32.SetFilePointer() retval=00000000 ret=00404da9 0024:Call KERNEL32.GetFileSize(00000074,00000000) ret=004040e2 0024:Ret KERNEL32.GetFileSize() retval=0000355c ret=004040e2 0024:Call ntdll.RtlAllocateHeap(00110000,00000008,0000355d) ret=00404155 0024:Ret ntdll.RtlAllocateHeap() retval=001b7ba8 ret=00404155 0024:Call KERNEL32.ReadFile(00000074,001b7ba8,0000355c,0033d4b0,00000000) ret=00404174 0024:Ret KERNEL32.ReadFile() retval=00000001 ret=00404174 ... 0024:Call KERNEL32.lstrlenW(code=c0000005 flags=0 addr=0xf75b21e1 ip=f75b21e1 tid=0024 0024:trace:seh:raise_exception info[0]=00000000 0024:trace:seh:raise_exception info[1]=001d0000 0024:trace:seh:raise_exception eax=001d0000 ebx=f774f000 ecx=8a7a124c edx=001b7ba8 esi=7b87d584 edi=0000355c 0024:trace:seh:raise_exception ebp=0033d2d8 esp=0033d2a0 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010216 0024:trace:seh:call_stack_handlers calling handler at 0x7bc9dcbf code=c0000005 flags=0 0024:trace:seh:__regs_RtlUnwind code=c0000005 flags=2 0024:trace:seh:__regs_RtlUnwind calling handler at 0x7bc81a39 code=c0000005 flags=2 0024:trace:seh:__regs_RtlUnwind handler at 0x7bc81a39 returned 1 ... --- snip ---
The installer reads a file '0x0409.ini' which contains UTF-16 text and converts the content to ansi string.
--- snip --- $ file 0x0409.ini 0x0409.ini: Little-endian UTF-16 Unicode text, with CRLF, CR line terminators
$ ls -l 0x0409.ini -rw-rw-r--. 1 focht focht 13660 Mar 27 2008 0x0409.ini --- snip ---
Strangely the read/conversion is done multiple times on the same file. It works the first 3 times which shuffle the heap a bit.
The installer allocates filesize()+1 bytes with HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size).
Before ReadFile() on buffer:
NOTE: I dumped the leading/trailing bytes to show the heap block metadata, see 'USE' and 'FREE' magic.
--- snip --- Address Hex dump ASCII $-0x10 00 00 00 00|00 00 00 00|60 35 00 00|55 53 45 03| USE $ 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| $+0x10 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ... $+0x3550 00 00 00 00|00 00 00 00|00 00 00 00|00 73 6B 00| $+0x3560 61 0C 0B 00|46 52 45 45|88 00 11 00|28 01 11 00| FREE --- snip ---
You can already spot the problem here: '00 73 6B 00' -> the first byte was zero-init from HEAP_ZERO_MEMORY. The rest are left-over from previous use of the block (alloc -> free -> alloc).
After ReadFile() of 13660 (0x355C) bytes on buffer:
BOM at beginning, followed by actual UTF-16 data.
--- snip --- Address Hex dump ASCII $-10 00 00 00 00|00 00 00 00|60 35 00 00|55 53 45 03| USE $ FF FE 0D 00|0A 00 5B 00|30 00 78 00|30 00 34 00| [ 0 x 0 4 $+10 30 00 39 00|5D 00 0D 00|0A 00 54 00|49 00 54 00| 0 9 ] ... $+0x3550 69 00 65 00|64 00 29 00|0D 00 0A 00|00 73 6B 00| $+0x3560 61 0C 0B 00|46 52 45 45|88 00 11 00|28 01 11 00| FREE --- snip ---
The installer calls lstrlenW() on the buffer, uses the length information to allocate a new, stack based buffer and then calls WideCharToMultiByte().
lstrlenW() triggers a page fault in unmapped area in search of wide-character NULL terminator because the adjacent block which is marked "FREE" contains garbage until the end of mapping.
Regards