http://bugs.winehq.org/show_bug.cgi?id=18601
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net
--- Comment #2 from Anastasius Focht focht@gmx.net 2009-05-24 06:30:34 --- Hello,
it's not that easy as you think... and it affects many apps that use browser control. In short: wrong handling of TLS slots in urlmon leads to "reuse" of TLS slots with undefined behaviour in other Wine components (crash at best).
Another app suffering from this: "BinTube" (http://www.bintube.com/player/)
Trace log:
--- snip --- ... 0035:Call user32.PeekMessageW(0032c860,00000000,00000100,0000010f,00000000) ret=08c3b480 0035:Call imm32.ImmProcessKey(00030144,04090409,00000020,00390001,00000000) ret=603cc93f 0035:Call KERNEL32.TlsGetValue(00000000) ret=791ae8cf 0035:Ret KERNEL32.TlsGetValue() retval=001f3348 ret=791ae8cf 0035:Call user32.GetPropW(00030144,791b76c0 L"WineImmHIMCProperty") ret=791b2bb4 0035:Ret user32.GetPropW() retval=00000000 ret=791b2bb4 0035:Call KERNEL32.TlsGetValue(00000000) ret=791ae8cf 0035:Ret KERNEL32.TlsGetValue() retval=001f3348 ret=791ae8cf 0035:trace:seh:raise_exception code=c0000005 flags=0 addr=0x791b2beb ip=791b2beb tid=0035 0035:trace:seh:raise_exception info[0]=00000001 0035:trace:seh:raise_exception info[1]=00000006 0035:trace:seh:raise_exception eax=00030144 ebx=791b94dc ecx=00000000 edx=00000002 esi=0032c384 edi=0032c2f4 0035:trace:seh:raise_exception ebp=0032c188 esp=0032c140 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010202 ... --- snip ---
TLS slot 0 is the interesting one. It's allocated early by IMM. Different run in winedbg, hence different TID:
--- snip --- Wine-dbg>bt Backtrace: =>0 0x7b882040 TlsSetValue(index=0, value=0x1d28d8) [/opt/wine/wine-git/dlls/kernel32/process.c:2421] in kernel32 (0x0033a958) 1 0x60a3c055 ImmGetContext+0x6f(hWnd=(nil)) [/opt/wine/wine-git/dlls/imm32/imm.c:1380] in imm32 (0x0033a9a8) 2 0x6087fe5f IME_UpdateAssociation+0x1d(focus=(nil)) [/opt/wine/wine-git/dlls/winex11.drv/ime.c:1036] in winex11 (0x0033a9c8) 3 0x608b94c7 open_xim+0x977(display=0x7c7952a8) [/opt/wine/wine-git/dlls/winex11.drv/xim.c:502] in winex11 (0x0033aac8) 4 0x608b956b X11DRV_SetupXIM+0x2a() [/opt/wine/wine-git/dlls/winex11.drv/xim.c:517] in winex11 (0x0033ab08) 5 0x608adeed x11drv_init_thread_data+0x1ea() [/opt/wine/wine-git/dlls/winex11.drv/x11drv_main.c:660] in winex11 (0x0033ab38) ... --- snip ---
TID to be sure:
--- snip --- Wine-dbg>info thread process tid prio (all id:s are in hex) ... 0000001e (D) C:\Program Files\BinTube\BinTube Usenet Reader Pro\BinPlayer.exe 00000025 0 00000024 0 00000023 2 00000022 0 0000001f 0 <== ... --- snip ---
"Reuse" of TLS slot 0 by Gecko:
--- snip --- Wine-dbg>bt Backtrace: =>0 0x7b882040 TlsSetValue(index=0, value=0x20d218) [/opt/wine/wine-git/dlls/kernel32/process.c:2421] in kernel32 (0x0033b698) 1 0x04c8071e in nspr4 (+0x1071e) (0x0033b6b8) 2 0x04c80765 in nspr4 (+0x10765) (0x0033b6c8) 3 0x04c7568b in nspr4 (+0x568b) (0x0033b6d8) 4 0x0817b148 in xul (+0xbcb148) (0x0033b6f8) 5 0x0817b167 in xul (+0xbcb167) (0x0033b718) 6 0x0826d137 in xul (+0xcbd137) (0x0033b728) 7 0x075b10e1 in xul (+0x10e1) (0x0033b748) 8 0x7bc47ffd call_dll_entry_point+0x15() in ntdll (0x0033b768) 9 0x7bc4a3c9 MODULE_InitDLL+0x211(wm=0x208c70, reason=1, lpReserved=(nil)) [/opt/wine/wine-git/dlls/ntdll/loader.c:969] in ntdll (0x0033b8c8) 10 0x7bc4a757 process_attach+0x197(wm=0x208c70, lpReserved=(nil)) [/opt/wine/wine-git/dlls/ntdll/loader.c:1058] in ntdll (0x0033b928) 11 0x7bc4a703 process_attach+0x143(wm=0x1fde50, lpReserved=(nil)) [/opt/wine/wine-git/dlls/ntdll/loader.c:1050] in ntdll (0x0033b988) 12 0x7bc4d3df LdrLoadDll+0x88(path_name=0x208ab0, flags=0, libname=0x33ba28, hModule=0x33b9f0) [/opt/wine/wine-git/dlls/ntdll/loader.c:2015] in ntdll (0x0033b9b8) 13 0x7b86c9a3 load_library+0x118(libname=0x33ba28, flags=0) [/opt/wine/wine-git/dlls/kernel32/module.c:875] in kernel32 (0x0033ba08) ... --- snip ---
TID to be sure it's the same thread:
--- snip --- Wine-dbg>info thread process tid prio (all id:s are in hex) ... 0000001e (D) C:\Program Files\BinTube\BinTube Usenet Reader Pro\BinPlayer.exe 00000025 0 00000024 0 00000023 2 00000022 0 0000001f 0 <== ... --- snip ---
My first thought was: "oops, someone corrupted TLS bitmap?" but it wasn't the case. There was indeed a TLS free on slot 0 in between!
--- snip --- TlsFree () at /opt/wine/wine-git/dlls/kernel32/process.c:2353 2353 { Wine-dbg>bt Backtrace: =>0 0x7b881f22 TlsFree(index=0) [/opt/wine/wine-git/dlls/kernel32/process.c:2353] in kernel32 (0x0033c228) 1 0x71f06bcb get_notif_hwnd+0x17() [/opt/wine/wine-git/dlls/urlmon/bindprot.c:138] in urlmon (0x0033c278) 2 0x71f05fe5 Binding_Create+0xa6(mon=0x1fe018, binding_ctx=(nil), url=0x206b68, pbc=0x20bc18, to_obj=1, riid=0x60e05c34, binding=0x33c334) [/opt/wine/wine-git/dlls/urlmon/binding.c:1371] in urlmon (0x0033c2d8) 3 0x71f0657f start_binding+0x50(mon=0x1fe018, binding_ctx=(nil), url=0x206b68, pbc=0x20bc18, to_obj=1, riid=0x60e05c34, ret=0x33c390) [/opt/wine/wine-git/dlls/urlmon/binding.c:1463] in urlmon (0x0033c358) 4 0x71f069bf bind_to_object+0x46(mon=0x1fe018, url=0x206b68, pbc=0x20bc18, riid=0x60e05c34, ppv=0x33c434) [/opt/wine/wine-git/dlls/urlmon/binding.c:1539] in urlmon (0x0033c398) 5 0x71f1cac0 URLMoniker_BindToObject+0x137(iface=0x1fe018, pbc=0x20bc18, pmkToLeft=(nil), riid=0x60e05c34, ppv=0x33c434) [/opt/wine/wine-git/dlls/urlmon/umon.c:212] in urlmon (0x0033c3e8) 6 0x60df38d0 bind_to_object+0x286(This=0x1d2120, mon=0x1fe018, url=0x1c6ed8, bindctx=0x20bc18, callback=0x1c7928) [/opt/wine/wine-git/dlls/shdocvw/navigate.c:620] in shdocvw (0x0033c4e8) 7 0x60df3ae9 navigate_bsc+0x147(This=0x1d2120, bsc=0x1c7928, mon=(nil)) [/opt/wine/wine-git/dlls/shdocvw/navigate.c:656] in shdocvw (0x0033c538) 8 0x60df3b85 navigate_bsc_proc+0x4a(This=0x1d2120, t=0x1c6ec0) [/opt/wine/wine-git/dlls/shdocvw/navigate.c:680] in shdocvw (0x0033c568) 9 0x60de89fc process_dochost_task+0x20(This=0x1d2120, lparam=1863360) [/opt/wine/wine-git/dlls/shdocvw/dochost.c:45] in shdocvw (0x0033c588) 10 0x60df4836 shell_embedding_proc+0xb2(hwnd=0xd00c6, msg=1792, wParam=0, lParam=1863360) [/opt/wine/wine-git/dlls/shdocvw/oleobject.c:65] in shdocvw (0x0033c5c8) --- snip ---
This free leads to reuse of TLS slot 0 by different component, assigning other data structures. When IMM later queries TLS slot 0 because it still thinks it owns it bogus values are retrieved leading to crash.
The offending code :
--- snip dlls/urlmon/urlmon_main.c --- tls_data_t *get_tls_data(void) { tls_data_t *data;
if(!urlmon_tls) { DWORD tls = TlsAlloc(); tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, 0); if(tls != urlmon_tls) TlsFree(tls); }
data = TlsGetValue(urlmon_tls); if(!data) { data = heap_alloc_zero(sizeof(tls_data_t)); if(!data) return NULL;
EnterCriticalSection(&tls_cs); list_add_tail(&tls_list, &data->entry); LeaveCriticalSection(&tls_cs);
TlsSetValue(urlmon_tls, data); }
return data; } --- snip dlls/urlmon/urlmon_main.c --
TLS slot 0 is a valid value hence you can't use "zero" value as "TLS slot not allocated yet" (use TLS_OUT_OF_INDEXES or a flag). Applies to InterlockedCompareExchange() and urlmon_tls comparisons scattered throughout the code. Also trying to free the slot doesn't make sense here.
You might want to check other Wine components for incorrect "!tls_slot" idioms.
Regards