http://bugs.winehq.org/show_bug.cgi?id=27431
Summary: GetModuleFileNameW behaves unexpectedly when applications use a hardcoded hmodule=0x10000000 Product: Wine Version: unspecified Platform: x86 OS/Version: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: kernel32 AssignedTo: wine-bugs@winehq.org ReportedBy: rswarbrick@gmail.com
Created an attachment (id=35079) --> (http://bugs.winehq.org/attachment.cgi?id=35079) Log file as described in the report
SUMMARY: ========
Some code stupidly assumes that the hModule parameter describing the current exe is always 0x10000000. On my system, at least, this isn't true. The software then fails to work properly when it calls GetModuleFileName.
WHAT I FOUND / TO REPRODUCE: ============================
I'm trying to get the Onzo energy meter software [1] working and was confused by messages like:
12:55:57: Debug: src/helpers.cpp(140): 'CreateActCtx' failed with error 0x0000007b (no more data available).
appearing on the stderr. It turns out that this is a wxPython message from a failing call to CreateActCtx. The Onzo software is closed-source, but the code in helpers.cpp that's calling CreateActCtx is probably what you get from downloading something at [2]. In particular, it might well be the following:
static ULONG_PTR wxPySetActivationContext() {
OSVERSIONINFO info; wxZeroMemory(info); info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&info); if (info.dwMajorVersion < 5) return 0;
ULONG_PTR cookie = 0; HANDLE h; ACTCTX actctx; TCHAR modulename[MAX_PATH];
GetModuleFileName(wxGetInstance(), modulename, MAX_PATH); wxZeroMemory(actctx); actctx.cbSize = sizeof(actctx); actctx.lpSource = modulename; actctx.lpResourceName = MAKEINTRESOURCE(2); actctx.hModule = wxGetInstance(); actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID;
h = CreateActCtx(&actctx); if (h == INVALID_HANDLE_VALUE) { wxLogLastError(wxT("CreateActCtx")); return 0; }
if (! ActivateActCtx(h, &cookie)) wxLogLastError(wxT("ActivateActCtx"));
return cookie; }
After staring at debug logs for a bit, I realised that GetModuleFileName was storing "" into modulename and returning 0. Note the bullet-proof code in wxPython checking whether this happens...
Anyway, I then instrumented GetModuleFileName to find out what was going on (in a rather low-tech way) adding a line
fprintf (stderr, "hmodule = %p; lpFN = %p; size = %d\n", hModule, lpFileName, size);
near the start of the function and, once I'd realised that it was LdrFindEntryForAddress that failed, also printing out a line of the form
fprintf (stderr, "nts = %x\n", nts);
just after it was called. The resulting debug log included lines looking like this:
hmodule = 0x10000000; lpFN = 0x32daa0; size = 260
and it seems that wxGetInstance() is stupidly returning 0x10000000, which I recognise from my 1990's Windows-using days and think is what you always used to get, so maybe it's hardcoded somewhere. This is presumably either in wxPython or in Onzo's code (the wxGetInstance() basically just returns the value of a global variable that can be changed by wxSetInstance(), I think).
I'm going to attach a log that I created using this slightly-instrumented wine build with the command
WINEDEBUG=+actctx,+file,+module /opt/wine/bin/wine onzo_uploader.exe 2>~/LOG
The lines I'm talking about are just above line 13630. The extra "Address ranges searched" lines come from slightly instrumenting LdrFindEntryForAddress:
NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod) { PLIST_ENTRY mark, entry; PLDR_MODULE mod;
fprintf (stderr, "Address ranges searched:\n");
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) { mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
fprintf (stderr, " %p -> %p\n", mod->BaseAddress, mod->BaseAddress + mod->SizeOfImage);
...}}
which I did to check my guess was right about the base address being nonsense.
IDEAS FOR FIXING ================
I'm not sure what the correct way to go about fixing this is. I suppose one thing is to check that this really is due to Onzo/wxPython doing something stupid rather than Wine telling their software an incorrect base address somewhere else. I'm not quite sure how to go about doing that.
If it is just a hard-coding that actually works on Windows (I presume that Windows's ASLR doesn't mess it up?), maybe LdrFindEntryForAddress needs to hardcode its answer for 0x10000000? But that's really really horrible... Ideas??
Rupert
[1] http://download.sse.co.uk/OnzoDownloader/onzo_uploader_latest.msi [2] http://www.wxpython.org/download.php