Haskell DLL causes memory leak

Viewed 185

I am working on a C++ project that uses a Haskell DLL (GHC version is 8.0.1 x64). I've noticed, that the executing program consumes much memory. I investigated into the matter and that's what I've found out. Let's consider the following minimal example. Here is a little project that consists of three files.

HaskellExports.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module HaskellExports where

import Foreign.C.Types
import Foreign.StablePtr

foreign export ccall foo :: CInt -> IO (StablePtr Int)

foo :: CInt -> IO (StablePtr Int)
foo (CInt n) = newStablePtr (fromIntegral n)

Contains a function that is supposed to be called from a C/C++ code.

CWrapper.cpp

#define DLLExport extern "C" __declspec(dllexport) 

DLLExport void* c_smth (const int num)
{
    return 0;
}

I intentionally didn't include the real exports of the Haskell functions, because they make no difference to this example.

main.cpp

#include <Windows.h>

int main()
{
    for (;;)
    {
        HINSTANCE module = ::LoadLibrary(L"HaskellExports.dll");
        ::FreeLibrary(module);
    }
    return 0;
}

Here, in an endless loop, I load the library and free it at once. Let's try to build the DLL in two different ways. First, let's not include the Haskell object file:

ghc -c HaskellExports.hs
ghc -c CWrapper.cpp 
ghc -shared -no-hs-main -o HaskellExports.dll CWrapper.o

I've run the program and noticed (with the help of Windows process monitor), that the memory resources are captured and released properly.

Now let's also add the Haskell object file:

ghc -c HaskellExports.hs
ghc -c CWrapper.cpp 
ghc -shared -no-hs-main -o HaskellExports.dll CWrapper.o HaskellExports.o

I've run the program again and noticed, that it consumes more and more memory in length of time with no intention to release it. This situation leads to a crash.

What am I doing wrong?

P.S. Further investigation showed that memory leak is caused only when HaskellExport.hs contains at least one foreign export function.

1 Answers

I decided to send an e-mail to ghc-devs mailing list. (To read all correspondence, see the question and further messages, the answer can be found here).

The brief explanation. The memory leak is caused due to the following: for each foreign export RTS creates a static C wrapper, which is initialized on DLL_PROCESS_ATTACH, but it has no finalizer/destructor to be called during DLL_PROCESS_DETACH. So it will stay alive till the program termination.

Related