3
votes

I am trying to use some functions from Intel's MKL library, in a program written with Embarcadero C++ Builder 2010. I'm running into some odd behaviour where calling any one of the MKL methods silently terminates the application. It turns out that the library is calling TerminateProcess() when any method is called. I'm having some trouble finding exactly where the app terminates, because stepping into the MKL method and tracing instruction by instruction in the CPU view calls into the TerminateProcess method at different places every time.

My guess is that this is an error condition caught by the library. As far as I can tell, it is called from within the MKL library, not from any other part of the RTL or an external error routine or anywhere else.

What might cause this? Has anyone successfully used the MKL with a C++Builder program?

Symptoms

I have the following code, based on the Two-dimensional FFT (C Interface) example:

DFTI_DESCRIPTOR_HANDLE hDesc;
MKL_LONG alDimensions[2];
alDimensions[0] = 32; // Array dimensions
alDimensions[1] = 100;
MKL_LONG lStatus = DftiCreateDescriptor(&hDesc, DFTI_SINGLE, DFTI_COMPLEX, 2, alDimensions);

The program appeared to vanish uncaught by the debugger when calling into DftiCreateDescriptor. So, to investigate, I stepped into the function and walked through the assembly. It jumps to MKL_RT.DftiCreateDescriptor_s_md, and then I can page through ten or more pages of assembly. At some point, it will call an address that turns out to be TerminateProcess. However, the point at which it does this feels random. At one point, for example, I narrowed it down to one call statement and address, only to have it crash before I got there next time I ran the program. Edit: Since I first asked this question, I placed breakpoints at ExitProcess, TerminateProcess, TerminateThread, etc, and found that it is calling TerminateProcess. (Originally I didn't know why it terminated silently.) The point at which it does so still changes. There is no useful call stack (this is the test program, source below):

:7540d79a kernel32.TerminateProcess
:5be911c9 ; C:\projects\mkl crash\Debug\MKL_RT.DLL
:5be837bd ; C:\projects\mkl crash\Debug\MKL_RT.DLL
:004013C5 main(argc=1, argv=:008B9908)
:32ad2342 ; C:\Windows\SysWOW64\CC32100.DLL

(Those two MKL_RT.dll lines, when examined in the CPU view, don't appear to be in the right methods. Chances are this is because it's release code and the debugger isn't tracing the call stack properly... or it could be related to the problem.)

I've reproduced this with several other MKL methods too. Using the FFTW3 compatibility interface, it sometimes occurs calling fftwf_malloc (and sometimes doesn't), and always occurs when calling fftwf_plan_dft_2d.

More details

  • I am using the latest version, 2013 SP1. I installed only the IA32 components (since CB2010 is a 32-bit only compiler.)
  • I am linking with the single-DLL linking option, linking to mkl_rt.dll.
  • However, since mkl_rt.lib is a COFF file, I generated a new .lib using implib -a mkl_rt.lib mkl_rt.dll. It created an apparently fine library, although warned about hundreds of duplicate symbols.
  • Commenter greatwolf below suggested a different implib command, implib -a -c mkl_rt.lib mkl_rt.dll, to preserve method name case. This caused far fewer duplicate name warnings, but won't link: [ILINK32 Error] Fatal: Exceeded memory limit for block Import symbols in module _vsrnggumbel
  • I have also tried loading the library and functions dynamically, in case there was a problem with the .lib file, method prototypes, etc (eg, loading and directly calling DftiCreateDescriptor_s_md from the DLL.) The behaviour is unchanged.
  • The C interface for the DLL uses cdecl calling convention, which is what the project options are set to use by default, and stepping into the calling code for a method I see all the parameters being pushed on the stack. Each function appears to be being called correctly.
  • Changing my dynamically loaded prototype to stdcall (even though it should be finding the cdecl version) caused the same problem - but it was worth checking. The DLL, mkl_rt.dll, supports mostly only the cdecl versions.
  • The IDE is not set to ignore any exceptions. In the Tools > Options > Debugger Options > Embarcadero Debuggers > Native OS Exceptions section, all exceptions are set to be handled by the debugger.

Reproducing

Here is a simple command-line C program that is enough to demonstrate the crash:

#include <stdio.h>
#pragma hdrstop

#include <tchar.h>
// Intel MLK
#include "mkl/include/mkl.h"
#pragma comment(lib, "mkl/mkl_rt.lib") // Generated with implib

int _tmain(int argc, _TCHAR* argv[]) {
    DFTI_DESCRIPTOR_HANDLE hDesc;
    MKL_LONG lStatus;
    MKL_LONG alDimensions[2];
    alDimensions[0] = 32; 
    alDimensions[1] = 100;
    lStatus = DftiCreateDescriptor(&hDesc, DFTI_SINGLE, DFTI_COMPLEX, 2, alDimensions);

    // Here, you would normal declare your arrays (32x100) of _Complex, and call DftiCommitDescriptor,
    // DftiComputeForward, DftiFreeDescriptor - but it will have already terminated
    // on the line above.

    return 0;
}

The BCB command line the IDE builds this with is:

c:\program files (x86)\embarcadero\rad studio\7.0\bin\bcc32.exe -D_DEBUG -D_RTLDLL;_NO_VCL -I"..." -y -Q -k -r- -c -tWC -C8 -oDebug\mkltest.obj -w-par -Od -v -vi- -H=Debug\MKLTest.pch -H mkltest.c

and linking:

c:\program files (x86)\embarcadero\rad studio\7.0\bin\ilink32.exe -LDebug;"...";"..." -lDebug -v -G8 c0x32 Debug\mkltest.obj , Debug\MKLTest.exe , Debug\MKLTest.map , import32.lib cw32i.lib , ,

Where I omitted a huge number of include paths. For the same of completeness, the entire lines are:

c:\program files (x86)\embarcadero\rad studio\7.0\bin\bcc32.exe -D_DEBUG -D_RTLDLL;_NO_VCL -I"C:\Program Files (x86)\EurekaLab\EurekaLog 6\Cbuilder14";C:\projects\Misc\DirectX\Direct3D\Tutorials\Tut05_Textures;"C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\include\boost_1_39\boost\tr1\tr1";"c:\program files (x86)\embarcadero\rad studio\7.0\include";"c:\program files (x86)\embarcadero\rad studio\7.0\include\dinkumware";"c:\program files (x86)\embarcadero\rad studio\7.0\include\vcl";"C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\include\boost_1_39";"c:\program files (x86)\embarcadero\rad studio\7.0\include";"c:\program files (x86)\embarcadero\rad studio\7.0\include\vcl";"c:\program files (x86)\embarcadero\rad studio\7.0\ObjRepos\Cpp";"c:\program files (x86)\embarcadero\rad studio\7.0\include\Indy10";"c:\program files (x86)\embarcadero\rad studio\7.0\Virtual Treeview\Common";"c:\program files (x86)\embarcadero\rad studio\7.0\Virtual Treeview\Source";"c:\program files (x86)\embarcadero\rad studio\7.0\Virtual Treeview\Delphi";"c:\program files (x86)\embarcadero\rad studio\7.0\include\boost_1_39";"c:\program files (x86)\embarcadero\rad studio\7.0\Toolbar2000\TB2K\Lib\D12";"c:\program files (x86)\embarcadero\rad studio\7.0\Toolbar2000\SpTBXLib\Source";"c:\program files (x86)\embarcadero\rad studio\7.0\AutomatedQADocking\Source";"C:\Program Files (x86)\TMS Advanced Poly List";"C:\Program Files (x86)\TMS Advanced Poly List\Builder2010";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\CBuilder14";"c:\program files (x86)\embarcadero\rad studio\7.0\Abbrevia\source" -y -Q -k -r- -c -tWC -C8 -oDebug\mkltest.obj -w-par -Od -v -vi- -H=Debug\MKLTest.pch -H mkltest.c

and linking:

c:\program files (x86)\embarcadero\rad studio\7.0\bin\ilink32.exe -LDebug;"c:\program files (x86)\embarcadero\rad studio\7.0\lib\debug";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\Cbuilder14";C:\projects\Misc\DirectX\Direct3D\Tutorials\Tut05_Textures;"c:\program files (x86)\embarcadero\rad studio\7.0\lib";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\obj";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\psdk";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\CBuilder14";"c:\program files (x86)\embarcadero\rad studio\7.0\lib";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\psdk";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\Indy10";"c:\program files (x86)\embarcadero\rad studio\7.0\Toolbar2000\TB2K\Lib\D12";"c:\program files (x86)\embarcadero\rad studio\7.0\AutomatedQADocking\Source";"C:\Program Files (x86)\TMS Advanced Poly List";"C:\Program Files (x86)\TMS Advanced Poly List\Builder2010";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\CBuilder14";"C:\Users\Public\Documents\RAD Studio\7.0\DCP" -jDebug;"c:\program files (x86)\embarcadero\rad studio\7.0\lib\debug";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\Cbuilder14";C:\projects\Misc\DirectX\Direct3D\Tutorials\Tut05_Textures;"c:\program files (x86)\embarcadero\rad studio\7.0\lib";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\obj";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\psdk";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\CBuilder14";"c:\program files (x86)\embarcadero\rad studio\7.0\lib";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\psdk";"c:\program files (x86)\embarcadero\rad studio\7.0\lib\Indy10";"c:\program files (x86)\embarcadero\rad studio\7.0\Toolbar2000\TB2K\Lib\D12";"c:\program files (x86)\embarcadero\rad studio\7.0\AutomatedQADocking\Source";"C:\Program Files (x86)\TMS Advanced Poly List";"C:\Program Files (x86)\TMS Advanced Poly List\Builder2010";"C:\Program Files (x86)\EurekaLab\EurekaLog 6\CBuilder14";"C:\Users\Public\Documents\RAD Studio\7.0\DCP" -lDebug -v -G8 c0x32 Debug\mkltest.obj , Debug\MKLTest.exe , Debug\MKLTest.map , import32.lib cw32i.lib , ,

Final note: I just added the [delphi] tag, since it uses the same RTL, in case that is related. I'm using RAD Studio 2010, which includes both C++ Builder and Delphi. The main app I'm putting the MKL into is written with both languages. The test app above is pure C.

1
I don't have MKL installed atm to reproduce this but an avenue you can explore is to see if this also happens with msvc or mingw. If there are no crashes, you can crack open their compiled disassembly and see where the difference lies. Maybe there's some convention that isn't being followed by borland during the call?greatwolf
For completeness can you also include the bcc32 command used to compile the test case?greatwolf
@greatwolf, I've added the bcc32 command line. Also I don't have MSVC or mingw installed at the moment, and am using internet over a tethered mobile right now - it may be hard to install them for a few days until I get proper internet, sorry.David
I started by creating the def file using something like impdef mkl.def mkl_rt.dll. Then I removed all the stdcall decorated functions (with the @xx suffix), following that with implib -a -c mkl.lib mkl.def.greatwolf
I've posted it to gist.greatwolf

1 Answers

1
votes

I am having exactly the same problem with mkl_rt.dll and Borland and, you guessed it, DftiCreateDescriptor.

I suspect it has something to do with the mkl threading.
In any case, my solution will be to wrap the mkl calls in a 32 bit Visual Studio DLL. I will make myself that I know Borland can run. The Visual Studio DLL will statically link mkl, but needs libiomp5md.dll. I know this works, because I am already basically doing that.