Opened 2 years ago

Closed 2 years ago

#10885 closed bug (duplicate)

Crashes on FFI calls to Visual Studio-built C library

Reported by: mwu Owned by:
Priority: high Milestone:
Component: Compiler Version: 7.10.1
Keywords: Cc: tmcdonell
Operating System: Windows Architecture: x86_64 (amd64)
Type of failure: Runtime crash Test Case:
Blocked By: Blocking:
Related Tickets: #10726 Differential Rev(s):
Wiki Page:

Description (last modified by mwu)

I want to call third-party C library using ffi on Windows. Everything works fine with 32-bit GHC distribution, however 64-bit program crashes as soon the ffi call is being made. Interestingly, the same program works when run with runghc. Just the compiled .exe crashes.

Consider the following C++ library code:

// adder.cpp

extern "C"
{
        __declspec(dllexport) int _cdecl add(int a, int b)
        {
                return a + b;
        }
}

and the following Haskell code using the library:

import Foreign.C

foreign import ccall unsafe "add" add :: CInt -> CInt -> IO CInt

main = (add 5 2) >>= print

It does work on 32-bit architecture and in ghci (on all architectures). Why does it not work as 64-bit executable?

Notes:

  • it works if the library is built with MinGW. However, this is not an acceptable workaround for me, since the library I want to call is external and closed-source
  • the problem seems to be related to the import library file handling — if I replace the MSVC-generated one with the MinGW-generated .lib import library, it works (even with MSVC-generated .dll)

Repro

I attach archive repro_src.7z with source files (as presented here) and a build.bat script building binaries. It needs to have both GCC/GHC and MSVC compilers in the path. (so it should be called from MSVC's x64 Native Tools Command Prompt)

It creates two folder — in one it builds the library with MinGW, in the another one — with MSVC. The Haskell program crashes only with MSVC build of library. However, the Haskell source file works fine with runghc/ghci. Run the build.bat and ender the bin-msvc directory. The Caller.exe program crashes. However, runghc -ladder ..\src\Caller.hs gives the expected result.

If you don't have MSVC installed, I provide also a package with all the C++ sources built — repro_bin.7z. I have used Microsoft Visual Studio 2013 and MinGHC 7.10.1, both 64-bit targeting. Same happens with GHC 7.8.4.

Please let me know, if you need any further information to investigate this report.

Attachments (2)

repro_src.7z (528 bytes) - added by mwu 2 years ago.
repro_bin.7z (60.1 KB) - added by mwu 2 years ago.

Download all attachments as: .zip

Change History (12)

Changed 2 years ago by mwu

Attachment: repro_src.7z added

Changed 2 years ago by mwu

Attachment: repro_bin.7z added

comment:1 Changed 2 years ago by mwu

Description: modified (diff)

comment:2 Changed 2 years ago by tmcdonell

Cc: tmcdonell added

comment:3 Changed 2 years ago by rwbarton

I hardly know anything about Windows and its calling conventions (for example I have no idea how OSMinGW32 is a possible platform when compiling 64-bit code) but a while ago I noticed at https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention something about a shadow space which as far as I can see we don't take into account in genCCall64'. Could this be the cause?

comment:4 Changed 2 years ago by mwu

@rwbarton

From what I see OSMinGW32 is just an OS name (meaning simply "Windows") and has no relation to the 32/64-bit targeting (i.e. targeted architecture).

The shadow space you mention is interesting. I know little about GHC inner workings and calling conventions, so take my speculations with a grain of salt. Still, from what I understand, both MinGW and MSVC on x64 Windows use the same calling convention. If it was the problem, it should fail with both.

Moreover, Haskell code is able to correctly call x64 MSVC-built dll. The problem seems to be related only to the MSVC-generated import library (the .lib file). You might want to compare MinGW's and MSVC's adder.lib files in the repro_bin.7z package I uploaded. With one, calling add method works, with another one it crashes. I'd suspect that difference should be somewhere there.

Last edited 2 years ago by mwu (previous) (diff)

comment:5 Changed 2 years ago by rwbarton

Yuras pointed out that I missed this bit of code

    -- On Win64, we also have to leave stack space for the arguments
    -- that we are passing in registers
    lss_code <- if platformOS platform == OSMinGW32
                then leaveStackSpace (length (allArgRegs platform))
                else return nilOL

which seems to deal correctly with the shadow space.

comment:6 Changed 2 years ago by awson

This is a bug in binutils. It can't link MS-created 64-bit import libraries properly.

The bug was fixed in latest MSys2 binutils distribution: http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-binutils-2.25.1-1-any.pkg.tar.xz.

Note that the bugfix was not in vanilla 2.25.1. MSys2 maintainers backported it from trunk binutils.

The bug is described here: https://sourceware.org/bugzilla/show_bug.cgi?id=16598

Last edited 2 years ago by awson (previous) (diff)

comment:7 Changed 2 years ago by mwu

Thanks for the answer, good to know that the bug is already fixed in the MSYS2. Would it be possible to ship the corrected version of binutils in next GHC Windows releases?

comment:8 Changed 2 years ago by awson

It's done already.

At the moment you can safely replace them manually.

comment:9 Changed 2 years ago by mwu

That's great. I can confirm that replacing binutils binaries with the ones from the MSys2 distribution you linked does solve the issue. :-)

Looking forward to see a build with updated MinGW distribution, the dated GCC 4.5/4.6 gave us some other headaches as well.

comment:10 Changed 2 years ago by thomie

Resolution: duplicate
Status: newclosed
Note: See TracTickets for help on using tickets.