http://bugs.winehq.org/show_bug.cgi?id=9056
--- Comment #14 from Anastasius Focht focht@gmx.net 2007-09-15 15:53:38 --- Hello again,
well actually there are more bugs in mono and wine regarding the assembly loading mechanism. Start your engines ...
used: mono 1.2.5 win32 wine-0.9.44-379-g82ef8d7
After using the AOT cache and msvcrt._wspawnvp() workaround i stumbled over .NET gui app (windows forms) which uses pinvoke() calls to user32.dll. The loader tries to locate the user32.dll and crashes.
--- snip --- ... fixme:msvcrt:_wspawnvp stub Mono-INFO: Assembly Loader loaded assembly from location: 'C:\Program Files\Mono-1.2.5\lib\mono\gac\Mono.Posix\2.0.0.0__0738eb9f132ed756\Mono.Posix.dll'. Mono-INFO: Config attempting to parse: 'C:\Program Files\Mono-1.2.5\lib\mono\gac\Mono.Posix\2.0.0.0__0738eb9f132ed756\Mono.Posix.dll.config'. Mono-INFO: Config attempting to parse: 'C:\Program Files\Mono-1.2.5\lib..\etc\mono\assemblies\Mono.Posix\Mono.Posix.config'. Mono-INFO: Assembly Ref addref System.Windows.Forms 00196660 -> Mono.Posix 001922E8: 2 Mono-INFO: DllImport attempting to load: 'user32.dll'. Mono-INFO: DllImport loading location: 'user32.dll.dll'. Stacktrace:
at System.Windows.Forms.XplatUIWin32.GetInstance () <0xffffffff> at System.Windows.Forms.XplatUIWin32.GetInstance () <0x00020> at System.Windows.Forms.XplatUI..cctor () <0x000b8> at (wrapper runtime-invoke) System.Windows.Forms.Application.runtime_invoke_void (object,intptr,intptr,intptr) <0xffffffff> at System.Windows.Forms.Application.EnableVisualStyles () <0xffffffff> at System.Windows.Forms.Application.EnableVisualStyles () <0x00008> at crc32_gui.Program.Main () <0x00008> at (wrapper runtime-invoke) crc32_gui.Program.runtime_invoke_void (object,intptr,intptr,intptr) <0xffffffff> --- snip ---
Notice the message "DllImport loading location: 'user32.dll.dll'." Further search in mono source reveals this comes from mono/mono/metadata/loader.c:mono_lookup_pinvoke_call() which tries to load the module using a variety of names. This function calls mono/mono/utils/mono-dl.c:mono_dl_build_path() to return possible file names of the library. Well mono_dl_build_path() assumes the library parameter is the "base name of a library". Which is of course not the case: full name supplied instead. ".dll" is mistakenly appended for all assemblies.
Next the module should be loaded:
mono_lookup_pinvoke_call() -> cached_module_load() -> mono_dl_open()
It fails loading dll (LL_SO_OPEN -> w32_load_module -> LoadLibrary()). Of course: user32.dll.dll wont work. It tries then again with ".la" suffix appended and fails again.
Now the interesting part, the error handling. When an error is encountered, LL_SO_ERROR() is called which should return a formatted (system) error message (pointer to buffer). LL_SO_ERROR maps to "w32_dlerror" which is this code:
--- snip mono-1-2-5/mono/mono/utils/mono-dl.c --- static char* w32_dlerror (void) { char* ret = NULL; wchar_t* buf = NULL; DWORD code = GetLastError ();
if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL)) { ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL); LocalFree (buf); } return ret; } --- snip mono-1-2-5/mono/mono/utils/mono-dl.c ---
Can you spot the bug? Hint: FORMAT_MESSAGE_ALLOCATE_BUFFER tells the callee to allocate memory. Well, try to store the returned buffer pointer in nirvana and fail miserably ;-)
So actually it's both: a mono and a wine bug. Mono should actually do FormatMessage( ...., &buf, ...) and Wine should actually watch for supplied NULL ptrs in FormatMessageA/W() before trying to access them (copy).
Now you might think "ok, that's it". No it isnt over yet ;-) After i quick-fixed wine's FormatMessageA/W to handle buf == NULL case (returning 0 length) mono crashed again. Well mono assumes if any error occurs a system generated error message must be returned. The logging mechanism depends on that. If it fails somehow, like the bug in mono code itself, which prevents FormatMessageA/W() from returning valid error msg buffer it crashes by deref null pointer.
--- snip pseudo code --- ret = call_some_native_func( ... &error_msg) if( !ret) { mono_trace( "... %s", error_msg); g_free (error_msg); } --- snip pseudo code ---
So there is currently no way to get around these issues without fixing mono source itself. Wine should fix the FormatMessageA/W() and msvcrt._wspawnvp() issues.
FOR THE RECORD: the code flow and issues are essentially the same on native windows platform (except for the FormatMessage bug). Start console (cmd.exe) there. Enable logging (set MONO_LOG_MASK=debug). Start mono.exe with some .net app (i used simple 2.0 .net app generated by VC2005/C#) and see it die. For more fun, enable AOT cache (set MONO_AOT_CACHE=1). Die.
Regards