[Bug 27431] New: GetModuleFileNameW behaves unexpectedly when applications use a hardcoded hmodule=0x10000000

wine-bugs at winehq.org wine-bugs at winehq.org
Thu Jun 9 07:27:15 CDT 2011


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 at winehq.org
        ReportedBy: rswarbrick at 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

-- 
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