Run-Time Check Failure #0: Using C-exports from Mi

2019-09-19 08:05发布

问题:

This question is about using C-Functions from a MinGW dll in a VC++ project, which fails with the following error: Run-Time Check Failure #0.

I successfully build clang and more importantly libclang using MinGW (to have a libclang.dll that uses the MinGW standard library).

My application previously used a VC++-build of libclang, that I now want to exchange with the MinGW build.

To do that, I created a def-file and afterwards an import library from the MinGW dll file:

dlltool -z libclang.def --export-all-symbol libclang.dll
dlltool -d libclang.def -l libclang.lib

Before creating the import library, I altered the def-file so it only contains the important clang-functions that have been declared using extern "C". Here is a small excerpt:

LIBRARY libclang.dll
EXPORTS
    clang_CXCursorSet_contains @ 50006
    clang_CXCursorSet_insert @ 50007
    clang_CXXMethod_isStatic @ 50008
    clang_CXXMethod_isVirtual @ 50009
    clang_Cursor_getTranslationUnit @ 50010

Using the MinGW dll and the new import library, I can now successfully compile my application. It runs and I can actually use some functions like "clang_createIndex", but whenever I get to "clang_getTranslationUnitCursor" I get a:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

The functions inside Clang's Index.h (and thus out of my control) are declared like this:

#ifdef _MSC_VER
  #ifdef _CINDEX_LIB_
    #define CINDEX_LINKAGE __declspec(dllexport)
  #else
    #define CINDEX_LINKAGE __declspec(dllimport)
  #endif
#else
  #define CINDEX_LINKAGE
#endif

CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);

I have actually no idea, why it works for some functions and not for others!

Thanks a lot!

[Update]

For lovers of assembly, here is some example assembly that leads to the crash. The call to clang_getNumDiagnostics works, the call to clang_getTranslationUnitCursor fails in the last line, when calling __RTC_CheckEsp - which is the function that checks the correctness of ESP

// call to clang_getNumDiagnostics(TU); - works!
5AF3EFAB  mov         esi,esp  
5AF3EFAD  mov         eax,dword ptr [ebp-30h]  
5AF3EFB0  push        eax  
5AF3EFB1  call        dword ptr [__imp__clang_getNumDiagnostics (5AF977E0h)]  
5AF3EFB7  add         esp,4  
5AF3EFBA  cmp         esi,esp  
5AF3EFBC  call        @ILT+7135(__RTC_CheckEsp) (5AF16BE4h)  
// call to clang_getTranslationUnitCursor(TU); - fails!
5AF3EFC1  mov         esi,esp  
5AF3EFC3  mov         eax,dword ptr [ebp-30h]  
5AF3EFC6  push        eax  
5AF3EFC7  lea         ecx,[ebp-234h]  
5AF3EFCD  push        ecx  
5AF3EFCE  call        dword ptr [__imp__clang_getTranslationUnitCursor (5AF9780Ch)]  
5AF3EFD4  add         esp,8  
5AF3EFD7  cmp         esi,esp  
5AF3EFD9  call        @ILT+7135(__RTC_CheckEsp) (5AF16BE4h)  

During the call of clang_getTranslationUnitCursor the esp will be increased by 4. The big question is, for both function calls which take the same parameter, why is it "add esp,4" after the the call to clang_getNumDiagnostics, but "add esp,8" when calling clang_getTranslationUnitCursor??