Thread overview
[Issue 1695] New: Calling some functions out of PSAPI.dll corrupts stack
Nov 28, 2007
d-bugmail
Dec 30, 2007
d-bugmail
[Issue 1695] implib produces wrong *.lib files
Oct 21, 2012
Denis Shelomovskij
Oct 21, 2012
Denis Shelomovskij
Apr 07, 2013
Walter Bright
November 28, 2007
http://d.puremagic.com/issues/show_bug.cgi?id=1695

           Summary: Calling some functions out of PSAPI.dll corrupts stack
           Product: D
           Version: 2.007
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: critical
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: mail@tobias-wassermann.de


1. Generate a lib with implib: implib /noi /system psapi.lib C:\windows\system32\psapi.lib

2. Compile the following code with dmd ProcessFinder.d -L+psapi/noi

import std.stdio;
import std.c.windows.windows;

extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle,
uint dwProcessId);

extern (C)
{
  BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned);
  DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName,
uint size);
  DWORD GetProcessImageFileNameA(HANDLE hProcess, LPSTR lpImageFileName, DWORD
nSize);
}

void main(char[][] args)
{
  uint[256] processIds;
  uint byteCount;
  char[] processFileName;
  int ret = EnumProcesses(processIds.ptr, processIds.length*uint.sizeof,
&byteCount);
  if(ret!=0)
  {
    for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++)
    {
      if(processIds[i]==0)
        continue;
      uint pid =  processIds[i];
      writefln("Process #%d - PID: %d", i, pid);

      HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */,
false, pid);
      if(cast(int)hProcess>0)
      {
        processFileName.length = 300;
        uint namelength = 0;
        //namelength = GetProcessImageFileNameA(hProcess, processFileName.ptr,
processFileName.length);
        namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0,
processFileName.ptr, processFileName.length);
        processFileName.length = namelength;
        writefln("=> %s", processFileName);
        CloseHandle(hProcess);
      }
    }
  }
}

So what will happen? With commented out GetModuleFileNameExA()-call you will get a list of correct process id's:

Process #1 - PID: 4
Process #2 - PID: 780
Process #3 - PID: 836

If you use GetModuleFileNameExA() the list will be incorrect:

Process #1 - PID: 4
Process #2 - PID: 780
Process #3 - PID: 836
Process #4 - PID: 4298544
Process #6 - PID: 1244976
Process #7 - PID: 4202711
Process #8 - PID: 1040
Process #9 - PID: 1288
Process #10 - PID: 1332

Process #4 to Process #8: These are invalid process id's - processes with these id doesn't exist, the next real id is 1288.

3. After calling GetModuleFileNameExA() the stack will be corrupted, the processIds-Array will be incorrect, if you comment out this call, all works fine. The same behaviour if you call GetProcessImageFileNameA()

Strange thing: If you port the code to C and compile against DMC - same problem! If you compile it with Microsoft Visual C++, you can also use GetModuleFileNameExA() and GetProcessImageFileNameA() without any problems. Seems to be an implib-issue?

See also the "Windows API: Strange behaviour after calling GetModuleFileNameExA" entries within the digitalmars.D-newsgroup


-- 

December 30, 2007
http://d.puremagic.com/issues/show_bug.cgi?id=1695


bugzilla@digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID




------- Comment #1 from bugzilla@digitalmars.com  2007-12-30 00:55 -------
The problem is declaring Windows API functions as being extern(C). They should
be extern(Windows). Stack corruption is the result of incorrectly declaring
what function calling convention to use.


-- 

October 21, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=1695


Denis Shelomovskij <verylonglogin.reg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
                 CC|                            |verylonglogin.reg@gmail.com
            Version|2.007                       |unspecified
         Resolution|INVALID                     |
            Summary|Calling some functions out  |implib produces wrong *.lib
                   |of PSAPI.dll corrupts stack |files


--- Comment #2 from Denis Shelomovskij <verylonglogin.reg@gmail.com> 2012-10-21 14:58:05 MSD ---
(In reply to comment #1)
> The problem is declaring Windows API functions as being extern(C). They should
> be extern(Windows). Stack corruption is the result of incorrectly declaring
> what function calling convention to use.

Looks like Walter like spending people time. As "extern(Windows)" and "extern(C)" functions has different symbol names the fact that the program links, runs and corrupts the stack just shows that `implib` generates incorrect *.lib files.


Incorrect behavior example (DLL):

implib /noi /system psapi-from-dll.lib %windir%\system32\psapi.dll

---
pragma(lib, "psapi-from-dll.lib");

extern(C) nothrow extern void EnumProcesses(); // links fine

void main()
{
    auto p = &EnumProcesses;
}
---


More than that 'implib' works incorrect with '.def' files too.
Incorrect behavior example (DEF):

psapi.def (from mingw except library name is "PSAPI" instead of "PSAPI.DLL" because 'implib' stops on dot with error):
---
LIBRARY PSAPI
EXPORTS
EnumProcesses@12
---

implib /noi /system psapi-from-def.lib psapi.def

---
pragma(lib, "psapi-from-def.lib");

// Error 42: Symbol Undefined _EnumProcesses
// or _EnumProcesses@12 for extern(Windows)
extern(C) nothrow extern void EnumProcesses(int, int, int);

void main()
{
    auto p = &EnumProcesses;
}
---

The second issue is because 'implib' ignores '/system' switch for *.def files:

implib /noi psapi-from-def-no-system.lib psapi.def

produces exactly same *.lib file.



The second issue has trivial workaround: one should prefix all symbols in *.def file with '_' by hands. E.g. such *.def file finally forces 'implib' to produce a correct *.lib:
---
LIBRARY PSAPI
EXPORTS
_EnumProcesses@12
---

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 21, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=1695



--- Comment #3 from Denis Shelomovskij <verylonglogin.reg@gmail.com> 2012-10-21 15:03:45 MSD ---
Damn, sorry. This is the correct DEF file for 'implib':
---
LIBRARY PSAPI
EXPORTS
_EnumProcesses@12=EnumProcesses
---
(or the program will link but fail to run trying to search for '_EnumProcesses@12' symbol in psapi.dll)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 07, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1695


Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|                            |WONTFIX


--- Comment #4 from Walter Bright <bugzilla@digitalmars.com> 2013-04-07 01:23:20 PDT ---
All /system does is prepend a _. See:

http://www.digitalmars.com/ctg/implib.html

The trouble is that the names in Windows systems DLLs use the extern (Windows)
calling convention, but they don't use the extern (Windows) mangled names. The
Windows mangled names have the @nn suffix.

The names happen to match up with the C names, but the stack treatment is different, hence the crash.

There is nothing implib can do about this situation. The only thing you, as a user, can do is create a correct module definition file in order to map the internal and external names. Implib can't do that, as it doesn't have the information to do it.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------