[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