[Bug 46022] New: MechWarrior Online (MWO, Piranha games) crashes before login (broken Boost 1.62.0+ boost:: context library corrupts TEB 'SubSystemTib')
wine-bugs at winehq.org
wine-bugs at winehq.org
Fri Oct 19 18:21:05 CDT 2018
https://bugs.winehq.org/show_bug.cgi?id=46022
Bug ID: 46022
Summary: MechWarrior Online (MWO, Piranha games) crashes before
login (broken Boost 1.62.0+ boost::context library
corrupts TEB 'SubSystemTib')
Product: Wine
Version: 3.18
Hardware: x86-64
OS: Linux
Status: NEW
Severity: normal
Priority: P2
Component: ntdll
Assignee: wine-bugs at winehq.org
Reporter: focht at gmx.net
Distribution: ---
Hello folks,
reported here: https://spcr.netlify.com/app/342200
Download: https://mwomercs.com/game/download
--- snip ---
$ pwd
/home/focht/wine-games/wineprefix64-mwo/drive_c/Program Files (x86)/Piranha
Games/MechWarrior Online/Bin64
$ file *
crashrpt_lang.ini: Little-endian UTF-16 Unicode text, with CRLF line
terminators
CrashSender1402.exe: PE32+ executable (GUI) x86-64, for MS Windows
CryRenderD3D11.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
CryRenderD3D9.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
D3DCompiler_43.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows
d3dx11_43.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows
d3dx9_43.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
fmod_event64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
fmod_event_net64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
fmodex64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
msvcp100.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
msvcr100.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
MWOClient.exe: PE32+ executable (GUI) x86-64, for MS Windows
nvDXTLibrary.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
soundbackends: directory
steam_api64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
ts3client_win64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
Txaa.win64.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
xinput1_3.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
--- snip ---
Trace log (without relay), with small diagnostics added to internal function
'get_full_path_helper()' (ntdll helper):
--- snip ---
$ WINEDEBUG=+seh,+loaddll,+process,+msvcrt,+ntdll,+file,+msgbox wine
./MWOClient.exe >>log.txt 2>&1
...
006f:trace:file:RtlDosPathNameToNtPathName_U_WithStatus
(L"C:\\windows\\system32\\dinput8.dll",0x23da40,0x23da60,(nil))
006f:trace:file:RtlGetFullPathName_U (L"C:\\windows\\system32\\dinput8.dll" 520
0x23d6b0 0x23da60)
006f:trace:file:get_full_path_helper PEB cd=0x7bd24798
006f:trace:file:RtlDosPathNameToNtPathName_U_WithStatus
(L"C:\\windows\\system32\\dinput8.dll",0x23db40,0x23db60,(nil))
006f:trace:file:RtlGetFullPathName_U (L"C:\\windows\\system32\\dinput8.dll" 520
0x23d7b0 0x23db60)
006f:trace:file:get_full_path_helper PEB cd=0x7bd24798
006f:trace:ntdll:NtRemoveIoCompletion (0x594, 0x23e6f8, 0x23e6e8, 0x23e5a0,
0x23e598)
006f:trace:msvcrt:MSVCRT_strncpy_s (0x1db0f290 260 "../build_info.xml"
18446744073709551615)
006f:trace:msvcrt:MSVCRT_strncpy_s (0x1db0ed30 260 "../build_info.xml"
18446744073709551615)
006f:trace:msvcrt:pf_printf_a Format is: "%c.%c"
006f:trace:msvcrt:pf_printf_a Format is: "%c..%c"
006f:trace:msvcrt:MSVCRT__wfsopen (L"build_info.xml",L"rb")
006f:trace:msvcrt:msvcrt_get_flags L"rb"
006f:trace:msvcrt:MSVCRT__wsopen_dispatch path: (L"build_info.xml") oflags:
0x8000 shflags: 0x0040 pmode: 0x0000 fd*: 0x1db0df38 secure: 0
006f:trace:file:CreateFileW L"build_info.xml" GENERIC_READ FILE_SHARE_READ
FILE_SHARE_WRITE creation 3 attributes 0x1
006f:trace:file:RtlDosPathNameToNtPathName_U_WithStatus
(L"build_info.xml",0x1db0dc40,(nil),(nil))
006f:trace:file:RtlGetFullPathName_U (L"build_info.xml" 520 0x1db0d860 (nil))
006f:trace:file:get_full_path_helper TEB cd=0x97791a97923a0c89
006f:trace:seh:NtRaiseException code=c0000005 flags=0 addr=0x7bc71a80
ip=7bc71a80 tid=006f
006f:trace:seh:NtRaiseException info[0]=0000000000000000
006f:trace:seh:NtRaiseException info[1]=ffffffffffffffff
006f:trace:seh:NtRaiseException rax=000000007bc71a80 rbx=000000000dcdb61c
rcx=000000000dcdb61c rdx=000000007bcce8c0
006f:trace:seh:NtRaiseException rsi=000000007bd2414f rdi=000000007bd24110
rbp=000000001db0d860 rsp=000000001db0d6a0
006f:trace:seh:NtRaiseException r8=0000000000000000 r9=000000001db0cf80
r10=0000000000000000 r11=0000000000000000
006f:trace:seh:NtRaiseException r12=97791a97923a0c89 r13=0000000000000000
r14=0000000000000208 r15=000000001db0ddf0
006f:trace:seh:dwarf_virtual_unwind function 7bc71a80 base 0x7bc717f0 cie
0x7bce1960 len 14 id 0 version 1 aug 'zR' code_align 1 data_align -8 retaddr
%rip
006f:trace:seh:execute_cfa_instructions 7bc717f0: DW_CFA_def_cfa %rsp, 8
...
--- snip ---
Running with 'winedbg':
--- snip ---
Unhandled exception: page fault on read access to 0xffffffffffffffff in 64-bit
code (0x000000007bc71970).
0075:fixme:dbghelp:interpret_function_table_entry PUSH_MACHFRAME 6
0075:fixme:dbghelp:interpret_function_table_entry PUSH_MACHFRAME 6
Register dump:
rip:000000007bc71970 rsp:000000001d9ab370 rbp:000000001d9ab530 eflags:00010203
( R- -- I - - -C)
rax:000000007bc71970 rbx:000000000da31e7c rcx:000000000da31e7c
rdx:000000007bcce860
rsi:000000001d9ab530 rdi:000000000da31e7c r8:000000001d9ab530
r9:0000000000000000 r10:0000000000000003
r11:0000000080000000 r12:97791a97923a0c89 r13:0000000000000000
r14:0000000000000208 r15:000000001d9abac0
Stack dump:
0x000000001d9ab370: 17af47a36cb3e5ab ccba60f716e77a7c
0x000000001d9ab380: 7bd7ed87ae6ddeb1 2df8d41d9546ee7b
0x000000001d9ab390: 92220f8556529aa7 2a82c0a1d13db80e
0x000000001d9ab3a0: 4e32842048625517 7b16ee5bbc8abbe4
0x000000001d9ab3b0: b26049e40d726523 000000001d9ab530
0x000000001d9ab3c0: 000000001d9ab500 000000000da31e7c
0x000000001d9ab3d0: 0000000000000000 0000000000000208
0x000000001d9ab3e0: 000000001d9abac0 000000007bc72566
0x000000001d9ab3f0: 5436642d537e2f27 2d78c917ac98b6c1
0x000000001d9ab400: 2e1d1f0a8a008a46 f1950ce96645b9c3
0x000000001d9ab410: 5e4abfdc1f818236 a49834d0365bd1ef
0x000000001d9ab420: 4031f987418fcc3f 0000000000000000
Backtrace:
=>0 0x000000007bc71970 get_full_path_helper.part+0x180() in ntdll
(0x000000001d9ab530)
1 0x000000007bc72566 RtlGetFullPathName_U+0x215() in ntdll
(0x000000001d9ab500)
2 0x000000007bc7286d
RtlDosPathNameToNtPathName_U_WithStatus+0x1ac(dos_path="build_info.xml",
ntpath=0x1d9ab910, file_part=(nil), cd=(nil))
[/home/focht/projects/wine/mainline-src/dlls/ntdll/path.c:378] in ntdll
(0x000000001d9ab820)
3 0x000000007bc72c21 RtlDosPathNameToNtPathName_U+0x10(dos_path=<is not
available>, ntpath=<is not available>, file_part=<is not available>, cd=<is not
available>) [/home/focht/projects/wine/mainline-src/dlls/ntdll/path.c:438] in
ntdll (0x000000001d9ab850)
4 0x000000007b4514c1 CreateFileW+0x520() in kernel32 (0x000000001d9aba40)
5 0x00007f2423963c76 MSVCRT__wsopen_dispatch+0x3e5(path="build_info.xml",
oflags=0x8000, shflags=<is not available>, pmode=<is not available>,
fd=0x1d9abc08, secure=0)
[/home/focht/projects/wine/mainline-src/dlls/msvcr100/../msvcrt/file.c:2291] in
msvcr100 (0x000000001d9abbc0)
6 0x00007f24239640f3 MSVCRT__wsopen+0x32(path=<is not available>, oflags=<is
not available>, shflags=<is not available>)
[/home/focht/projects/wine/mainline-src/dlls/msvcr100/../msvcrt/file.c:2387] in
msvcr100 (0x000000001d9abc10)
7 0x00007f2423969349 MSVCRT__wfsopen+0xb8(path=<is not available>, mode="rb",
share=0x40)
[/home/focht/projects/wine/mainline-src/dlls/msvcr100/../msvcrt/file.c:4141] in
msvcr100 (0x000000001d9abd20)
8 0x00007f2423969757 MSVCRT__wfopen+0x16(path=<is not available>, mode=<is
not available>)
[/home/focht/projects/wine/mainline-src/dlls/msvcr100/../msvcrt/file.c:4218] in
msvcr100 (0x000000001d9abd50)
9 0x0000000037e24854 in mwoclient (+0xe24853) (0x000000001d9abef0)
10 0x0000000037e1dac2 in mwoclient (+0xe1dac1) (0x000000001d9abef0)
0x000000007bc71970 get_full_path_helper.part+0x180 in ntdll: movq
0x0000000000000008(%r12),%r8
--- snip ---
--- snip ---
006f:trace:file:get_full_path_helper PEB cd=0x7bd24798
...
006f:trace:msvcrt:MSVCRT__wfsopen (L"build_info.xml",L"rb")
...
006f:trace:file:RtlGetFullPathName_U (L"build_info.xml" 520 0x1db0d860 (nil))
006f:trace:file:get_full_path_helper TEB
--- snip ---
The main thread's TEB gets partially corrupted in between two API calls. The
crash is triggered due retrieval and access of per-thread current directory
structure members which is also not quite correct (see "FIXME: hack") - but
that's not the real problem here.
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/ntdll/path.c#l631
--- snip ---
631 /******************************************************************
632 * get_full_path_helper
633 *
634 * Helper for RtlGetFullPathName_U
635 * Note: name and buffer are allowed to point to the same memory spot
636 */
637 static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
638 {
639 ULONG reqsize = 0, mark = 0, dep = 0, deplen;
640 LPWSTR ins_str = NULL;
641 LPCWSTR ptr;
642 const UNICODE_STRING* cd;
643 WCHAR tmp[4];
644
645 /* return error if name only consists of spaces */
646 for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
647 if (!*ptr) return 0;
648
649 RtlAcquirePebLock();
650
651 if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */
652 cd = &((WIN16_SUBSYSTEM_TIB
*)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath;
653 else
654 cd =
&NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.DosPath;
655
656 switch (RtlDetermineDosPathNameType_U(name))
...
--- snip ---
https://source.winehq.org/git/wine.git/blob/HEAD:/include/winnt.h#l2442
--- snip ---
2442 typedef struct _NT_TIB
2443 {
2444 struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
2445 PVOID StackBase;
2446 PVOID StackLimit;
2447 PVOID SubSystemTib;
2448 union {
2449 PVOID FiberData;
2450 DWORD Version;
2451 } DUMMYUNIONNAME;
2452 PVOID ArbitraryUserPointer;
2453 struct _NT_TIB *Self;
2454 } NT_TIB, *PNT_TIB;
--- snip ---
https://source.winehq.org/git/wine.git/blob/HEAD:/include/winternl.h#l3029
--- snip ---
3029 /* The thread information for 16-bit threads */
3030 /* NtCurrentTeb()->SubSystemTib points to this */
3031 typedef struct
3032 {
3033 void *unknown; /* 00 unknown */
3034 UNICODE_STRING *exe_name; /* 04 exe module name */
3035
3036 /* the following fields do not exist under Windows */
3037 UNICODE_STRING exe_str; /* exe name string pointed to by exe_name
*/
3038 CURDIR curdir; /* current directory */
3039 WCHAR curdir_buffer[MAX_PATH];
3040 } WIN16_SUBSYSTEM_TIB;
--- snip ---
Relevant game threads:
--- snip ---
Numb ID Entry TEB RIP Name
4 C9 0000000037ED24E0 00007FFFFFE98000 00007FDB6BEE9A62 JobSystem_Worker..
40 F1 00000000004987A0 00007FFFFFE04000 00007FDB6BEE9A62
23 DD 0000000037ED24E0 00007FFFFFE48000 00007FDB6BEE9A62 GetRenderMesh..
Main BD 0000000038B5C538 00007FFFFFEA8000 00000000384C3AE4 Main
5 CA 0000000037ED24E0 00007FFFFFE94000 00007FDB6BEE9A62 JobSystem_Worker..
...
<more>
--- snip ---
TEB of main thread before corruption:
--- snip ---
$ ==> 00007FFFFFEA8000 000000000023FE20
$+8 00007FFFFFEA8008 0000000000240000 ; StackBase
$+10 00007FFFFFEA8010 0000000000142000 ; StackLimit
$+18 00007FFFFFEA8018 0000000000000000 ; SubSystemTib
$+20 00007FFFFFEA8020 0000000000000000
$+28 00007FFFFFEA8028 0000000000000000
$+30 00007FFFFFEA8030 00007FFFFFEA8000
$+38 00007FFFFFEA8038 0000000000000000
$+40 00007FFFFFEA8040 00000000000000BC
$+48 00007FFFFFEA8048 00000000000000BD
$+50 00007FFFFFEA8050 0000000000000000
--- snip ---
The app makes use of coroutines which are implemented using Boost's context lib
(boost::context).
Interesting read: https://www.italiancpp.org/2016/11/02/coroutines-internals/
App code disassembly
--- snip ---
mwoclient.sub_38BC2D20:
0000000038BC2D20 | mov rdx,qword ptr ds:[rdx+10] | ; new context -> rsp
0000000038BC2D24 | add rcx,10 |
0000000038BC2D28 | jmp <mwoclient.jump_fcontext> |
mwoclient.jump_fcontext:
0000000038BF5B30 | push rbp | ; save
0000000038BF5B31 | push rbx |
0000000038BF5B32 | push rsi |
0000000038BF5B33 | push rdi |
0000000038BF5B34 | push r15 |
0000000038BF5B36 | push r14 |
0000000038BF5B38 | push r13 |
0000000038BF5B3A | push r12 |
0000000038BF5B3C | mov r10,qword ptr gs:[30] | ; TEB
0000000038BF5B45 | mov rax,qword ptr ds:[r10+8] | ; Stack Base (bottom)
0000000038BF5B49 | push rax |
0000000038BF5B4A | mov rax,qword ptr ds:[r10+10] | ; Stack Limit (top)
0000000038BF5B4E | push rax |
0000000038BF5B4F | mov rax,qword ptr ds:[r10+1478] | ; memaddr stack
0000000038BF5B56 | push rax |
0000000038BF5B57 | mov rax,qword ptr ds:[r10+18] | ; SubSystemTib
0000000038BF5B5B | push rax |
0000000038BF5B5C | lea rsp,qword ptr ss:[rsp-A8] |
0000000038BF5B64 | test r9,r9 |
0000000038BF5B67 | je mwoclient.38BF5BB7 |
0000000038BF5B69 | stmxcsr dword ptr ss:[rsp+A0] |
0000000038BF5B71 | fnstcw word ptr ss:[rsp+A4] |
0000000038BF5B78 | movaps xmmword ptr ss:[rsp],xmm6 |
0000000038BF5B7C | movaps xmmword ptr ss:[rsp+10],xmm7 |
0000000038BF5B81 | movaps xmmword ptr ss:[rsp+20],xmm8 |
0000000038BF5B87 | movaps xmmword ptr ss:[rsp+30],xmm9 |
0000000038BF5B8D | movaps xmmword ptr ss:[rsp+40],xmm10 |
0000000038BF5B93 | movaps xmmword ptr ss:[rsp+50],xmm11 |
0000000038BF5B99 | movaps xmmword ptr ss:[rsp+60],xmm12 |
0000000038BF5B9F | movaps xmmword ptr ss:[rsp+70],xmm13 |
0000000038BF5BA5 | movaps xmmword ptr ss:[rsp+80],xmm14 |
0000000038BF5BAE | movaps xmmword ptr ss:[rsp+90],xmm15 |
0000000038BF5BB7 | xor r10,r10 |
0000000038BF5BBA | push r10 |
0000000038BF5BBC | mov qword ptr ds:[rcx],rsp |
0000000038BF5BBF | mov rsp,rdx | ; switch context data
0000000038BF5BC2 | pop r10 |
0000000038BF5BC4 | test r9,r9 |
0000000038BF5BC7 | je mwoclient.38BF5C17 |
0000000038BF5BC9 | ldmxcsr dword ptr ss:[rsp+A0] | ; restore new context
0000000038BF5BD1 | fldcw word ptr ss:[rsp+A4] |
0000000038BF5BD8 | movaps xmm6,xmmword ptr ss:[rsp] |
0000000038BF5BDC | movaps xmm7,xmmword ptr ss:[rsp+10] |
0000000038BF5BE1 | movaps xmm8,xmmword ptr ss:[rsp+20] |
0000000038BF5BE7 | movaps xmm9,xmmword ptr ss:[rsp+30] |
0000000038BF5BED | movaps xmm10,xmmword ptr ss:[rsp+40] |
0000000038BF5BF3 | movaps xmm11,xmmword ptr ss:[rsp+50] |
0000000038BF5BF9 | movaps xmm12,xmmword ptr ss:[rsp+60] |
0000000038BF5BFF | movaps xmm13,xmmword ptr ss:[rsp+70] |
0000000038BF5C05 | movaps xmm14,xmmword ptr ss:[rsp+80] |
0000000038BF5C0E | movaps xmm15,xmmword ptr ss:[rsp+90] |
0000000038BF5C17 | mov rcx,A8 |
0000000038BF5C1E | test r10,r10 |
0000000038BF5C21 | je mwoclient.38BF5C27 |
0000000038BF5C23 | add rcx,8 |
0000000038BF5C27 | lea rsp,qword ptr ss:[rsp+rcx] |
0000000038BF5C2B | mov r10,qword ptr gs:[30] | ; TEB
0000000038BF5C34 | pop rax |
0000000038BF5C35 | mov qword ptr ds:[r10+18],rax | ; new SubSystemTib
0000000038BF5C39 | pop rax |
0000000038BF5C3A | mov qword ptr ds:[r10+1478],rax |
0000000038BF5C41 | pop rax |
0000000038BF5C42 | mov qword ptr ds:[r10+10],rax | ; Stack Limit (top)
0000000038BF5C46 | pop rax |
0000000038BF5C47 | mov qword ptr ds:[r10+8],rax | ; Stack Base (bottom)
0000000038BF5C4B | pop r12 |
0000000038BF5C4D | pop r13 |
0000000038BF5C4F | pop r14 |
0000000038BF5C51 | pop r15 |
0000000038BF5C53 | pop rdi |
0000000038BF5C54 | pop rsi |
0000000038BF5C55 | pop rbx |
0000000038BF5C56 | pop rbp |
0000000038BF5C57 | pop r10 |
0000000038BF5C59 | mov rax,r8 |
0000000038BF5C5C | mov rcx,r8 |
0000000038BF5C5F | jmp r10 | ; 000000003750B790
...
mwoclient.sub_3750B790:
000000003750B790 | mov rcx,qword ptr ds:[rcx+8] |
000000003750B794 | mov rax,qword ptr ds:[rcx] |
000000003750B797 | jmp qword ptr ds:[rax+8] |
...
--- snip ---
Corrupted TEB 'SubSystemTib' member after the coroutine context was switched:
--- snip ---
$ ==> 00007FFFFFEA8000 000000000023FE20
$+8 00007FFFFFEA8008 0000000025A3FFF0 ; StackBase (ok)
$+10 00007FFFFFEA8010 0000000025A20050 ; StackLimit (ok)
$+18 00007FFFFFEA8018 0000000000000066 ; SubSystemTib (bad)
$+20 00007FFFFFEA8020 0000000000000000
$+28 00007FFFFFEA8028 0000000000000000
$+30 00007FFFFFEA8030 00007FFFFFEA8000
$+38 00007FFFFFEA8038 0000000000000000
$+40 00007FFFFFEA8040 00000000000000BC
--- snip ---
Matching source:
https://github.com/boostorg/context/blob/2cec475b489ca26a91a02a8cfd566646ba9c02e3/src/asm/jump_x86_64_ms_pe_masm.asm
--- snip ---
jump_fcontext PROC BOOST_CONTEXT_EXPORT FRAME
.endprolog
; prepare stack
lea rsp, [rsp-0118h]
IFNDEF BOOST_USE_TSX
; save XMM storage
movaps [rsp], xmm6
movaps [rsp+010h], xmm7
movaps [rsp+020h], xmm8
movaps [rsp+030h], xmm9
movaps [rsp+040h], xmm10
movaps [rsp+050h], xmm11
movaps [rsp+060h], xmm12
movaps [rsp+070h], xmm13
movaps [rsp+080h], xmm14
movaps [rsp+090h], xmm15
; save MMX control- and status-word
stmxcsr [rsp+0a0h]
; save x87 control-word
fnstcw [rsp+0a4h]
ENDIF
; load NT_TIB
mov r10, gs:[030h]
; save fiber local storage
mov rax, [r10+018h]
mov [rsp+0b0h], rax
; save current deallocation stack
mov rax, [r10+01478h]
mov [rsp+0b8h], rax
; save current stack limit
mov rax, [r10+010h]
mov [rsp+0c0h], rax
; save current stack base
mov rax, [r10+08h]
mov [rsp+0c8h], rax
mov [rsp+0d0h], r12 ; save R12
mov [rsp+0d8h], r13 ; save R13
mov [rsp+0e0h], r14 ; save R14
mov [rsp+0e8h], r15 ; save R15
mov [rsp+0f0h], rdi ; save RDI
mov [rsp+0f8h], rsi ; save RSI
mov [rsp+0100h], rbx ; save RBX
mov [rsp+0108h], rbp ; save RBP
mov [rsp+0110h], rcx ; save hidden address of transport_t
; preserve RSP (pointing to context-data) in R9
mov r9, rsp
; restore RSP (pointing to context-data) from RDX
mov rsp, rdx
IFNDEF BOOST_USE_TSX
; restore XMM storage
movaps xmm6, [rsp]
movaps xmm7, [rsp+010h]
movaps xmm8, [rsp+020h]
movaps xmm9, [rsp+030h]
movaps xmm10, [rsp+040h]
movaps xmm11, [rsp+050h]
movaps xmm12, [rsp+060h]
movaps xmm13, [rsp+070h]
movaps xmm14, [rsp+080h]
movaps xmm15, [rsp+090h]
; restore MMX control- and status-word
ldmxcsr [rsp+0a0h]
; save x87 control-word
fldcw [rsp+0a4h]
ENDIF
; load NT_TIB
mov r10, gs:[030h]
; restore fiber local storage
mov rax, [rsp+0b0h]
mov [r10+018h], rax
; restore current deallocation stack
mov rax, [rsp+0b8h]
mov [r10+01478h], rax
; restore current stack limit
mov rax, [rsp+0c0h]
mov [r10+010h], rax
; restore current stack base
mov rax, [rsp+0c8h]
mov [r10+08h], rax
mov r12, [rsp+0d0h] ; restore R12
mov r13, [rsp+0d8h] ; restore R13
mov r14, [rsp+0e0h] ; restore R14
mov r15, [rsp+0e8h] ; restore R15
mov rdi, [rsp+0f0h] ; restore RDI
mov rsi, [rsp+0f8h] ; restore RSI
mov rbx, [rsp+0100h] ; restore RBX
mov rbp, [rsp+0108h] ; restore RBP
mov rax, [rsp+0110h] ; restore hidden address of transport_t
; prepare stack
lea rsp, [rsp+0118h]
; load return-address
pop r10
; transport_t returned in RAX
; return parent fcontext_t
mov [rax], r9
; return data
mov [rax+08h], r8
; transport_t as 1.arg of context-function
mov rcx, rax
; indirect jump to context
jmp r10
jump_fcontext ENDP
---- snip ---
Git history of boost::context lib revealed several bugfixes to these context
save/restore routines. One was related to storing/restoring the wrong TEB
member (offset).
<= boost-1.64.0
https://github.com/boostorg/context/commit/50ebf5bd1160623cbbf169f6a5d7ddff04e9d1ef#diff-c23b00e64d17c4518158e142996754f1
--- quote ---
x64 Windows: store/load fiber local storage from correct offset
--- quote ---
https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
-> fixed with boost-1.65.0
But that was not the real problem.
Execution context setup helper:
https://github.com/boostorg/context/blob/2f320aa68b4908eeb9aedba91ec8a546be20b009/src/asm/make_x86_64_ms_pe_masm.asm
-> 'make_fcontext()' shows only partial initialization.
While debugging I've noticed several garbage (uninit) values in the memory
block used for setting up the coroutine/execution context which later made it
into actual register context for the thread/coroutine.
I came across this commit:
https://github.com/boostorg/context/commit/20d4a5ed5f98e2f6e230b0b511b0250e136889be#diff-faaffb70622383d6804ff482565634a0
--- quote ---
set fiber-storage to zero (Windows)
- fixes bug 12215
--- quote ---
https://svn.boost.org/trac10/ticket/12215
-> fixed with boost-1.62.0
That one actually is the problem. The "fix" reverted an earlier fixup-commit
(boost-1.61.0) which zero-initialized the context on Windows platform and now
only zero-init specific member.
https://github.com/boostorg/context/commit/a5c0c85df3ad0440729d909f099ffba5a824da90#diff-f79f65c94140e6a917e4a909f46f67c9
--- quote ---
nulled stack only for Windows
--- quote ---
Execution context memory is taken from 'fixedsize_stack::allocate()' which uses
'std::malloc()' which by design doesn't zero init.
Allocated block for new context: 0x20000 bytes via iternal call to
'CryMalloc()' which calls 'HeapAlloc()':
--- snip ---
301705F0 6C 00 00 00 00 14 00 14 08 00 02 00 55 53 45 08 l...........USE.
30170600 60 DB 13 30 00 00 00 00 70 2F 15 30 00 00 00 00 `Û.0....p/.0....
30170610 00 00 00 00 00 00 00 00 00 00 00 84 70 59 07 6F ............pY.o
30170620 62 6A 65 63 74 73 00 65 6E 76 69 72 6F 6E 6D 65 bjects.environme
30170630 6E 74 73 00 63 69 74 79 00 72 69 76 65 72 63 69 nts.city.riverci
30170640 74 79 5F 62 6C 6F 63 6B 73 5F 63 6F 6D 6D 65 72 ty_blocks_commer
30170650 63 69 61 6C 7A 6F 6E 65 5F 30 31 00 63 6F 6D 6D cialzone_01.comm
30170660 65 72 63 69 61 6C 7A 6F 6E 65 5F 30 31 2E 6D 74 ercialzone_01.mt
30170670 6C 00 00 00 00 14 00 14 00 00 00 08 00 00 00 00 l...............
30190430 73 74 72 69 61 6C 5F 36 66 6F 6F 74 5F 66 65 6E strial_6foot_fen
30190440 63 65 5F 64 5F 64 61 6D 01 00 00 00 00 00 00 00 ce_d_dam........
30190450 32 2E 63 67 66 00 00 00 00 14 00 14 00 00 00 08 2.cgf...........
30190460 00 00 00 00 00 70 4E 7B 54 C7 C8 00 00 BC 6F 01 .....pN{TÇÈ..¼o.
30190470 00 61 00 00 00 00 00 00 00 00 00 00 00 00 00 FC .a.............ü
30190480 5C 8F 0B 6F 62 6A 65 63 74 73 00 65 6E 76 69 72 \..objects.envir
...
30190500 66 00 00 00 00 00 00 00 00 06 17 30 00 00 00 00 f..........0....
30190510 00 06 17 30 00 00 00 00 A0 05 19 30 00 00 00 00 ...0.... ..0....
30190520 6E 6D 65 6E 74 73 00 63 69 74 79 00 72 69 76 65 nments.city.rive
30190530 72 63 69 74 79 5F 66 65 6E 63 65 73 00 72 69 76 rcity_fences.riv
30190540 65 72 63 69 74 79 5F 69 6E 64 75 73 74 72 69 61 ercity_industria
30190550 6C 5F 36 66 6F 6F 74 5F 66 65 6E 63 65 5F 64 5F l_6foot_fence_d_
30190560 90 B7 50 37 00 00 00 00 1A 5B BF 38 00 00 00 00 .·P7.....[¿8....
...
30190590 64 82 00 00 66 00 00 00 00 00 00 00 00 00 00 00 d...f...........
301905A0 E0 84 0F 39 00 00 00 00 00 00 00 00 73 00 65 6E à..9........s.en
301905B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
301905C0 00 00 00 00 00 00 00 00 A0 FF 01 00 00 00 00 00 ........ ÿ......
301905D0 A0 05 19 30 00 00 00 00 74 79 5F 69 6E 64 75 73 ..0....ty_indus
301905E0 74 72 69 61 6C 5F 36 66 6F 6F 74 5F 66 65 6E 63 trial_6foot_fenc
301905F0 65 5F 64 5F 64 61 6D 61 67 65 64 5F 72 65 76 65 e_d_damaged_reve
30190600 72 73 65 5F 6C 6F 64 32 79 66 06 00 46 52 45 45 rse_lod2yf..FREE
30190610 70 2F 15 30 00 00 00 00 10 03 96 00 00 00 00 00 p/.0............
...
--- snip --
0x301905A0 is passed to 'make_fcontext()' -> partial init
0x30190448 is passed to 'jump_fcontext()' -> setup new context
All XMM regs in new context get garbage (uninit) values from heap block.
Same for TEB members: values via 'pop rax' from new stack (see 'jump_fcontext'
assembly):
$+0 0000000030190500 0000000000000066 ; garbage new SubSystemTib (ought to
be fiber local storage, see my comments earlier)
$+8 0000000030190508 0000000030170600 ; restore new deallocation stack
$+10 0000000030190510 0000000030170600 ; restore new stack limit
$+18 0000000030190518 00000000301905A0 ; restore new stack base
Summarizing: It just works by chance on Windows and maybe sometimes on Wine,
depending on heap usage.
There are multiple ways to solve this:
Game vendor (Piranha games):
1) upgrade to newer Boost libary (>= boost-1.65.0). There will be still
corruption in TEB, now in 'FiberData' member but it wouldn't harm anymore for
per-thread curdir ('SubSystemTib')
2) additionally modify boost::context lib to zero init everything returned by
'fixedsize_stack::allocate()'
Wine:
1) zero init all large heap allocations by default, regardless if
HEAP_ZERO_MEMORY is passed or not -> out of question, not an option
2) Don't use TEB 'SubSystemTib' member for win32/64 (legacy win16 only) or wrap
in exception handler = awful hack, fall back to PEB 'ProcessParameters'
I've tested a patch which removes the legacy WIN16_SUBSYSTEM_TIB access in case
of win32/win64 and the client starts fine. A proper implementaton of per-thread
curdir for win32/win64 wouldn't help here anyway.
$ sha1sum MWOPortalInstaller.exe
2e243479cb476e7295ce6f825e6916c3dafea535 MWOPortalInstaller.exe
$ du -sh MWOPortalInstaller.exe
68M MWOPortalInstaller.exe
$ wine --version
wine-3.18-114-g417e94f199
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