Bug 5815 – Using -O is causing wrong code to be generated for extern(C) method call.
Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2011-04-06T10:55:00Z
Last change time
2015-06-09T01:31:14Z
Assigned to
nobody
Creator
opantm+spam
Comments
Comment #0 by opantm+spam — 2011-04-06T10:55:30Z
When attempting to call a Windows API function, PathRemoveFileSpecA, invalid results are returned when using the -O compiler flag. When using the same file, but without -O, the correct output is generated.
Test Case:
import std.stdio;
import std.c.windows.windows;
static const ushort MAX_PATH = 260;
extern(C) BOOL PathRemoveFileSpecA(LPTSTR);
static void TrimToNull(ref char[] String) {
for(int i = 0; i < String.length; i++)
if(String[i] == '\0') {
String = String[0..i];
return;
}
}
static char[] GetDirectoryPath(string FilePath) {
char[] Copy = FilePath.dup;
uint Result = PathRemoveFileSpecA(Copy.ptr);
TrimToNull(Copy);
return Copy;
}
int main(string[] args) {
string Path = "D:\\Test Path\\Test.exe";
auto Dir = GetDirectoryPath(Path);
writefln("Dir: " ~ Dir);
return 0;
}
Output without -O: "Dir: D:\Test Path"
Output with -O: "object.Error: Access Violation"
For this particular example, shlwapi.lib must be generated with Implib.exe and linked.
The version of DMD being used is 2.052. OS is Windows, and compiled with: "dmd testfile.d shlwapi.lib (-O)".
Comment #1 by bugzilla — 2011-04-06T13:11:33Z
x86_64 (i.e. 64 bit code) is not currently supported by DMD on Windows. Changing to x86.
Comment #2 by r.sagitario — 2011-04-06T14:09:38Z
> extern(C) BOOL PathRemoveFileSpecA(LPTSTR);
You are probably using the wrong calling convention here, it should be "extern(Windows)", which corresponds to __stdcall in while "extern(C)" is __cdecl in the SDK C++ headers.
Comment #3 by opantm+spam — 2011-04-08T19:29:19Z
(In reply to comment #1)
> x86_64 (i.e. 64 bit code) is not currently supported by DMD on Windows.
> Changing to x86.
Sorry, I did mean x86.
(In reply to comment #2)
> > extern(C) BOOL PathRemoveFileSpecA(LPTSTR);
>
> You are probably using the wrong calling convention here, it should be
> "extern(Windows)", which corresponds to __stdcall in while "extern(C)" is
> __cdecl in the SDK C++ headers.
As far as I can tell, the calling convention is C. According to MSDN, the header is "BOOL PathRemoveFileSpec(__inout LPTSTR pszPath)". As a comparison, GetCurrentDirectory (which uses extern(Windows)) is "DWORD WINAPI GetCurrentDirectory(__in DWORD nBufferLength, __out LPTSTR lpBuffer)". When using extern(Windows), it fails to compile due to an undefined symbol error.
Comment #4 by r.sagitario — 2011-04-08T23:22:01Z
If you look it up in shlwapi.h in the SDK, it is declared as
LWSTDAPI_(BOOL) PathRemoveFileSpecA(__inout LPSTR pszPath);
and LWSTDAPI_(BOOL) expands to 'extern "C" __declspec(dllimport) BOOL __stdcall'.
__stdcall translates to D as extern(Windows).
I have tried your code, and I get a link error with "extern(C)". I have used coff2implib to convert the library from the sdk, because I have had problems with implib on DLLs in the past, it especially misses a number of symbols.
With "extern(Windows)", I can link and run your code without problems.
Comment #5 by r.sagitario — 2011-04-08T23:23:56Z
> I have used coff2implib
sorry, it is called coffimplib and available from the digitalmars ftp area.
Comment #6 by opantm+spam — 2011-04-09T10:27:41Z
(In reply to comment #4)
> If you look it up in shlwapi.h in the SDK, it is declared as
>
> LWSTDAPI_(BOOL) PathRemoveFileSpecA(__inout LPSTR pszPath);
>
> and LWSTDAPI_(BOOL) expands to 'extern "C" __declspec(dllimport) BOOL
> __stdcall'.
> __stdcall translates to D as extern(Windows).
>
> I have tried your code, and I get a link error with "extern(C)". I have used
> coff2implib to convert the library from the sdk, because I have had problems
> with implib on DLLs in the past, it especially misses a number of symbols.
>
> With "extern(Windows)", I can link and run your code without problems.
Awesome. After getting coffimplib and converting with it instead as well as changing to extern(Windows), it works both with and without -O. :) Thanks for the help. I guess this bug report is invalid.