[Bug 21562] New: Multiple init/deinit of msvcrt (std fd's) causes pluto app installer to hang
wine-bugs at winehq.org
wine-bugs at winehq.org
Sun Jan 31 10:58:04 CST 2010
http://bugs.winehq.org/show_bug.cgi?id=21562
Summary: Multiple init/deinit of msvcrt (std fd's) causes pluto
app installer to hang
Product: Wine
Version: 1.1.37
Platform: x86
URL: http://pluto.brain-killer.org/download/pluto_FE_w32_en
_0036.exe
OS/Version: Linux
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: msvcrt
AssignedTo: wine-bugs at winehq.org
ReportedBy: focht at gmx.net
Hello,
an interesting one...
WINEDEBUG=+tid,+seh,+loaddll,+msvcrt,+server,+relay wine
./pluto_FE_w32_en_0036.exe >>log.txt 2>&1
The app installer creates an additional worker (unpack) thread from its main
thread:
--- snip ---
0009:Call
KERNEL32.CreateThread(00000000,00000000,0042b674,00000000,00000000,00436718)
ret=0042c3e8
0009: *fd* 6 <- 22
0009: new_thread( access=001f03ff, attributes=00000000, suspend=1, request_fd=6
)
0009: new_thread() = 0 { tid=001b, handle=0004 }
...
001b:Starting thread proc 0x42b674 (arg=(nil))
...
0009:Ret KERNEL32.CreateThread() retval=00000004 ret=0042c3e8
--- snip ---
The app installer main thread contains a loop to check if the (unpack) worker
thread (handle = 0x4) is still alive.
While doing so, it pumps messages and delays the next check, illustrated by
following code snippet:
--- snip ---
0009:Ret KERNEL32.Sleep() retval=00000000 ret=004167e4
0009:Call KERNEL32.GetExitCodeThread(00000004,0032fd9c) ret=0042c40f
0009: get_thread_info( handle=0004, tid_in=0000 )
0009: get_thread_info() = 0 { pid=0008, tid=001b, teb=7ffd4000,
affinity=ffffffffffffffff, creation_time=1caa28d3911cf76 (-0.0285120),
exit_time=0, exit_code=259, priority=0, last=0 }
0009:Ret KERNEL32.GetExitCodeThread() retval=00000001 ret=0042c40f
0009:Call user32.PeekMessageA(0032fd0c,00000000,00000000,00000000,00000001)
ret=004167d9
...
0009:Ret user32.PeekMessageA() retval=00000000 ret=004167d9
0009:Call KERNEL32.Sleep(00000001) ret=004167e4
--- snip ---
Unfortunately something goes wrong and the app installer refuses to terminate -
because the worker checking loop suddenly became a forever loop:
--- snip ---
...
0009:Call KERNEL32.Sleep(00000001) ret=004167e4
0009:Ret KERNEL32.Sleep() retval=00000000 ret=004167e4
0009:Call KERNEL32.GetExitCodeThread(00000004,0032fd9c) ret=0042c40f
0009: get_thread_info( handle=0004, tid_in=0000 )
0009: get_thread_info() = INVALID_HANDLE { pid=0000, tid=0000, teb=00000000,
affinity=00000000, creation_time=0, exit_time=0, exit_code=0, priority=0,
last=0 }
0009:Ret KERNEL32.GetExitCodeThread() retval=00000000 ret=0042c40f
0009:Call user32.PeekMessageA(0032fd0c,00000000,00000000,00000000,00000001)
ret=004167d9
0009: get_message( flags=00000001, get_win=00000000, get_first=00000000,
get_last=ffffffff, hw_id=00000000, wake_mask=00000000, changed_mask=00000000 )
0009: get_message() = PENDING { win=00000000, msg=00000000, wparam=00000000,
lparam=00000000, type=0, time=00000000, active_hooks=80000000, total=0, data={}
}
...
0009:Ret user32.PeekMessageA() retval=00000000 ret=004167d9
--- snip ---
The installer code doesn't evaluate the return code of GetExitCodeThread() but
instead accesses the exit code variable directly, comparing it to 0x103 ->
STILL_ACTIVE.
Because the thread once lived in this state, this variable is never touched by
Wine in case the thread handle becomes invalid.
GetExitCodeThread() fails but the variable still contains the last known "good"
value -> STILL_ACTIVE (the app doesn't reinit it).
The app still thinks the worker is alive and goes into forever loop.
Now the culprit: the thread handle, delivered to caller upon returning from
CreateThread() is _never_ closed by app explicitly -> CloseHandle() so
GetExitCodeThread() should be successful in any case.
We have to go back in time to unearth the problem ... lets look what happens to
this thread handle (0x4).
--- snip ---
...
001b:Call KERNEL32.FreeLibrary(10000000) ret=004242bb
001b:Call PE DLL (proc=0x10001148,module=0x10000000
L"unpack.dll",reason=PROCESS_DETACH,res=(nil))
001b:Ret PE DLL (proc=0x10001148,module=0x10000000
L"unpack.dll",reason=PROCESS_DETACH,res=(nil)) retval=1
001b:Call PE DLL (proc=0x5de0cc9c,module=0x5de00000
L"crtdll.dll",reason=PROCESS_DETACH,res=(nil))
001b:Ret PE DLL (proc=0x5de0cc9c,module=0x5de00000
L"crtdll.dll",reason=PROCESS_DETACH,res=(nil)) retval=1
001b:Call PE DLL (proc=0x5c7cd8b4,module=0x5c790000
L"msvcrt.dll",reason=PROCESS_DETACH,res=(nil))
...
001b:trace:msvcrt:DllMain (0x5c790000, DLL_PROCESS_DETACH, (nil)) pid(8),
tid(1b), tls(4)
001b:trace:msvcrt:msvcrt_free_mt_locks : uninitializing all mtlocks
...
001b:trace:msvcrt:MSVCRT__close :fd (3) handle (0xfffffff6)
001b:Call KERNEL32.CloseHandle(fffffff6) ret=5c7ad9fc
001b: close_handle( handle=0004 )
001b: close_handle() = 0
001b:Ret KERNEL32.CloseHandle() retval=00000001 ret=5c7ad9fc
001b:trace:msvcrt:msvcrt_free_fd :fd (3) freed
001b:trace:msvcrt:MSVCRT__close :ok
...
001b:trace:msvcrt:MSVCRT__close :fd (4) handle (0xfffffff5)
001b:Call KERNEL32.CloseHandle(fffffff5) ret=5c7ad9fc
001b: close_handle( handle=0008 )
001b: close_handle() = 0
001b:Ret KERNEL32.CloseHandle() retval=00000001 ret=5c7ad9fc
001b:trace:msvcrt:msvcrt_free_fd :fd (4) freed
001b:trace:msvcrt:MSVCRT__close :ok
...
001b:trace:msvcrt:MSVCRT__close :fd (5) handle (0xfffffff4)
001b:Call KERNEL32.CloseHandle(fffffff4) ret=5c7ad9fc
001b: close_handle( handle=000c )
001b: close_handle() = 0
001b:Ret KERNEL32.CloseHandle() retval=00000001 ret=5c7ad9fc
001b:trace:msvcrt:msvcrt_free_fd :fd (5) freed
001b:trace:msvcrt:MSVCRT__close :ok
001b:trace:msvcrt:MSVCRT__fcloseall :closed (3) handles
...
001b:trace:msvcrt:MSVCRT__close :fd (0) handle (0x8)
001b:Call KERNEL32.CloseHandle(00000008) ret=5c7ad9fc
001b: close_handle( handle=0008 )
001b: close_handle() = INVALID_HANDLE
001b:Ret KERNEL32.CloseHandle() retval=00000000 ret=5c7ad9fc
...
001b:warn:msvcrt:MSVCRT__close :failed-last error (6)
...
001b:trace:msvcrt:MSVCRT__close :ok
...
001b:trace:msvcrt:MSVCRT__close :fd (1) handle (0xc)
001b:Call KERNEL32.CloseHandle(0000000c) ret=5c7ad9fc
001b: close_handle( handle=000c )
001b: close_handle() = INVALID_HANDLE
001b:Ret KERNEL32.CloseHandle() retval=00000000 ret=5c7ad9fc
...
001b:warn:msvcrt:MSVCRT__close :failed-last error (6)
...
001b:trace:msvcrt:MSVCRT__close :ok
...
001b:trace:msvcrt:MSVCRT__close :fd (2) handle (0x50)
001b:Call KERNEL32.CloseHandle(00000050) ret=5c7ad9fc
001b: close_handle( handle=0050 )
001b: close_handle() = 0
001b:Ret KERNEL32.CloseHandle() retval=00000001 ret=5c7ad9fc
001b:trace:msvcrt:msvcrt_free_fd :fd (2) freed
001b:Call KERNEL32.GetStdHandle(fffffff4) ret=5c7ac729
001b:Ret KERNEL32.GetStdHandle() retval=0000000c ret=5c7ac729
001b:trace:msvcrt:MSVCRT__close :ok
...
001b:trace:msvcrt:msvcrt_free_console :Closing console handles
--- snip ---
*eek* ... the thread handle gets closed as part of msvcrt cleanup!
PROCESS_DETACH -> msvcrt_free_io() -> MSVCRT__fcloseall()
This will close fd(3), fd(4), fd(5) -> stdin,stdout,stderr
Corresponding msvcrt init:
--- snip ---
...
001b:Call PE DLL (proc=0x5c7cd8b4,module=0x5c790000
L"msvcrt.dll",reason=PROCESS_ATTACH,res=(nil))
...
001b:trace:msvcrt:DllMain (0x5c790000, DLL_PROCESS_ATTACH, (nil)) pid(8),
tid(1b), tls(0)
...
001b:Call KERNEL32.GetStartupInfoA(0096e4b8) ret=5c7acdd6
001b:Ret KERNEL32.GetStartupInfoA() retval=00000011 ret=5c7acdd6
001b:Call KERNEL32.GetStdHandle(fffffff6) ret=5c7acf77
001b:Ret KERNEL32.GetStdHandle() retval=00000004 ret=5c7acf77
001b:Call
KERNEL32.DuplicateHandle(ffffffff,00000004,ffffffff,5c7db2e0,00000000,00000001,00000002)
ret=5c7acfc0
001b: dup_handle( src_process=ffffffff, src_handle=0004, dst_process=ffffffff,
access=00000000, attributes=00000002, options=00000002 )
001b: dup_handle() = 0 { handle=0008, self=1, closed=0 }
001b:Ret KERNEL32.DuplicateHandle() retval=00000001 ret=5c7acfc0
001b:Call KERNEL32.GetStdHandle(fffffff5) ret=5c7acff6
001b:Ret KERNEL32.GetStdHandle() retval=00000008 ret=5c7acff6
001b:Call
KERNEL32.DuplicateHandle(ffffffff,00000008,ffffffff,5c7db304,00000000,00000001,00000002)
ret=5c7ad03f
001b: dup_handle( src_process=ffffffff, src_handle=0008, dst_process=ffffffff,
access=00000000, attributes=00000002, options=00000002 )
001b: dup_handle() = 0 { handle=000c, self=1, closed=0 }
001b:Ret KERNEL32.DuplicateHandle() retval=00000001 ret=5c7ad03f
001b:Call KERNEL32.GetStdHandle(fffffff4) ret=5c7ad075
001b:Ret KERNEL32.GetStdHandle() retval=0000000c ret=5c7ad075
001b:Call
KERNEL32.DuplicateHandle(ffffffff,0000000c,ffffffff,5c7db328,00000000,00000001,00000002)
ret=5c7ad0be
001b: dup_handle( src_process=ffffffff, src_handle=000c, dst_process=ffffffff,
access=00000000, attributes=00000002, options=00000002 )
001b: dup_handle() = 0 { handle=0050, self=1, closed=0 }
001b:Ret KERNEL32.DuplicateHandle() retval=00000001 ret=5c7ad0be
001b:trace:msvcrt:msvcrt_init_io :handles (0x8)(0xc)(0x50)
--- snip ---
The culprit: msvcrt is actually loaded and unloaded _two_ times!
Upon the first unload sequence all std/fd handles are teared down (including
handle 0x4) - this makes the handle values available in server again.
When the worker thread is created it gets the unused handle 0x4 assigned from
wineserver.
This is the handle which is then polled by installers GetExitCodeThread() loop.
When msvcrt is loaded a second time, GetStdHandle( STD_XXX) will still deliver
its original value from PEB (0x4, 0x8, 0xC).
Upon second msvcrt unload, fd(3), fd(4), fd(5) are closed again but this time
they close something completely different (indication are also fd close errors
following), leaving the app installer in forever loop.
Regards
--
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
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