http://bugs.winehq.org/show_bug.cgi?id=10467
--- Comment #1 from Anastasius Focht focht@gmx.net 2007-11-16 07:05:45 --- Created an attachment (id=9195) --> (http://bugs.winehq.org/attachment.cgi?id=9195) expose PEB loader lock to make .NET framework (ui) to work
Hello,
lets make further steps in this mine field :-)
Prerequisite:
1) wine-0.9.49 (or GIT) 2) successful installation of .NET 2.0 Framework 3) "l_intl.nls" copied from windows installation to wine system32
----
With that stuff in place, starting .NET gui apps will immediately lead to a crash.
--- snip --- 0:000> .exr -1 ExceptionAddress: 7a2bd897 (mscorwks!AuxUlibIsDLLSynchronizationHeld+0x00000074) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000000 Parameter[1]: 0000000c Attempt to read from address 0000000c --- snip ---
Not a CLR exception this time. Looks like ordinary NULL ptr dereference. But just in case let's look at CLR stack:
--- snip --- 0:000> !ClrStack OS Thread Id: 0xf (0) ESP EIP 0034f128 7a2bd897 [NDirectMethodFrameGeneric: 0034f128] System.Windows.Forms.UnsafeNativeMethods.IntCreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object) 0034f16c 039b44a5 System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object) 0034f1a8 039b089b System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams) 0034f228 02fafe53 System.Windows.Forms.Control.CreateHandle() 0034f288 02fae08b System.Windows.Forms.Application+MarshalingControl..ctor() 0034f290 02fadfea System.Windows.Forms.Application+ThreadContext.get_MarshalingControl() 0034f2c0 02fad783 System.Windows.Forms.WindowsFormsSynchronizationContext..ctor() 0034f2d0 02facec9 System.Windows.Forms.WindowsFormsSynchronizationContext.InstallIfNeeded() 0034f2fc 02fa9374 System.Windows.Forms.Control..ctor(Boolean) 0034f370 02fa8176 System.Windows.Forms.ScrollableControl..ctor() 0034f380 02fa8046 System.Windows.Forms.ContainerControl..ctor() 0034f390 02fa7e69 System.Windows.Forms.Form..ctor() 0034f3c8 02fa7132 Projekt2.WinForm..ctor() 0034f3d0 02fa710c Projekt2.WinForm.Main() 0034f5e4 79e88f63 [GCFrame: 0034f5e4] --- snip ---
Ok, somewhere after UnsafeNativeMethods.IntCreateWindowEx() (= native code transition) it crashes. Lets see native code callstack...
--- snip --- 0:000> kb ChildEBP RetAddr Args to Child 0034e98c 005704ea 0034e998 00570472 0012e100 mscorwks!AuxUlibIsDLLSynchronizationHeld+0x74 WARNING: Frame IP not in any known module. Following frames may be wrong. 0034e9a8 6043855a 00050056 00000024 00000000 0x5704ea 0034e9d8 60438bfe 00570472 00050056 00000024 user32!DeferWindowPos+0x2ea 0034ea18 6043de41 00050056 00000024 00000000 user32!DeferWindowPos+0x98e 0034ea58 60405e8a 00050056 00000024 00000000 user32!CallWindowProcA+0x1d1 0034eac8 60408dc2 0034ebe4 00000001 00000001 user32!GetMessagePos+0xda 0034eb28 6040923a 00000003 6045755e 00000001 user32!PeekMessageA+0xca2 0034eb68 60435228 00050056 00000024 00000000 user32!SendMessageW+0x4a 0034ec28 605e75f7 00050056 0034ed88 0034ed80 user32!WINPOS_GetMinMaxInfo+0x238 0034eda8 604321a7 00050056 0034f018 00000001 winex11!CreateWindow+0x327 0034f008 60433a9b 0000013e 0012e100 00000000 user32!SetWindowLongW+0x537 0034f048 79ef064c 00000000 00a14ee8 00000000 user32!CreateWindowExW+0x5b 0034f0e4 009ca83b 0012e100 0034f128 ff3b682a mscorwks!NDirectGenericStubReturnFromCall 0034f110 039b44a5 0034f1c8 00a14acc 00a14a8c 0x9ca83b 0034f16c 039b089b 00000000 00000000 11000000 0x39b44a5 0034f220 02fafe53 00a13e00 0000000e 0034f278 0x39b089b 0034f280 02fae08b 00a13e00 02fadfea 00a13a20 0x2fafe53 0034f2b8 02fad783 00000001 00a13928 00000000 0x2fae08b 0034f3d0 79e88f63 79e7c2ca 0034f414 0034f460 0x2fad783 0034f3d4 79e7c2ca 0034f414 0034f460 79e88ee4 mscorwks!CallDescrWorker+0x33 .. --- snip ---
Debugging the native code further, one comes to following code snippet.. I commented some parts for better readability:
--- snip --- mov eax, large fs:18h ; return the TEB address mov eax, [eax+30h] ; return the PEB address mov eax, [eax+0A0h] ; PEB+0xA0 -> void *LoaderLock -> PRTL_CRITICAL_SECTION LoaderLock push 1 add eax, 0Ch ; PEB->LoaderLock.OwningThread .. cmp dword ptr [eax], 0 ; PEB->LoaderLock.OwningThread *boom* .. --- snip ---
Well the code checks the PEB loader lock directly probably to prevent any ui deadlocks caused by multiple threads defer/nested loading ui controls. Wine does not expose its internal loader lock in PEB (NULL ptr), which leads to crash.
At this point wine has to make a design decision: expose the loader lock (critical section) in PEB or dismiss .NET :-) Unfortunately I don't see another way because if we fake the lock at this point by using a dummy one in order to protect the real loader lock it might cause various issues (both locks would have to be synchronized).
Attached is a patch which fixes this. It assigns the PEB loader lock field to wine internal loader lock at process startup (dlls/ntdll/loader.c:process_attach)
It works for me (tm) though AJ might find a better place for this. ---------------------------------------
Stay tuned, more goodies to come ...
Regards.