msys2 / MINGW-packages

Package scripts for MinGW-w64 targets to build under MSYS2.
https://packages.msys2.org
BSD 3-Clause "New" or "Revised" License
2.25k stars 1.21k forks source link

MinGW 32-bit Exception causes crash in DLL when standard libraries are statically linked #5763

Open kvnnap opened 5 years ago

kvnnap commented 5 years ago

This problem is very similar to this issue on stack overflow. In fact I am the author of that question, however I never truly understood what I did wrong.

I created a Windows DLL using the following code:

Header (dllexport.h):

#ifndef DLLEXPORT_H
#define DLLEXPORT_H

/* Define calling convention in one place, for convenience. */
#define ADDCALL __stdcall

/* Usually format is ADDAPI int ADDCALL Add(int a, int b)...
   but moving ADDCALL near ADDAPI works in gcc */

/* You should define BUILDING_DLL *only* when building the DLL. */
#ifdef BUILDING_DLL
  #define ADDAPI __declspec(dllexport) ADDCALL
#else
  #define ADDAPI __declspec(dllimport) ADDCALL
#endif

#ifdef  __cplusplus
extern "C" {
#endif

    ADDAPI int test();

#ifdef  __cplusplus
}
#endif

#endif  /* DLLEXPORT_H */

Implementation (main.cpp):

#include <cstdlib>
#include <windows.h>
#include <iostream>
#include "dllexport.h"

using namespace std;

ADDAPI int test()
{
    try
    {
        throw 2;
    }catch(...)
    {
        std::cout << "Caught" << std::endl;
        return 1;
    }
    return 0;
}

//Link to correct DllMain if C++ is used
#ifdef __cplusplus
extern "C"
#endif
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD  reason, LPVOID lpReserved)
{
    switch (reason)
    {
        case DLL_PROCESS_ATTACH:
        break;
        case DLL_THREAD_ATTACH:
        break;
        case DLL_THREAD_DETACH:
        break;
        case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Client (clientOOP.cpp)

#include <iostream>

#include "dllexport.h"

using namespace std;

int main() {
    cout << "Will test.. " << endl;
    int a = test();
    cout << "Test: " << a << endl;
    return 0;
}

Compilation steps:

DLL

g++ main.cpp -g -o mydll_s.dll -DBUILDING_DLL -shared -static-libgcc -static-libstdc++ -Wl,--add-stdcall-alias

Client

g++ clientOOP.cpp -g -o clientOOP.exe -L. -lmydll_s

When I run clientOOP.exe, get the following output and exits:

Will Test..

When debugging this, gdb reports it returned exit code 3. If I comment throw 2; it works as expected.

The problem does not occur if I also statically link libstdc++ and libgcc into the clientOOP executable, or if I do not statically link these libraries in the DLL at all.

I would like to understand why this happens. I know that one should not be throwing exceptions over DLL boundaries and I am not doing so. I am merely exposing a C interface, and everything C++-like is handled internally inside the DLL. As such, the call stack should be Dwarf2 aware in there. This scenario never happens on 64-bit MinGW or on Ubuntu 64/32 bit.

I did investigate trying to use this DLL within a pure-c program, and to my surprise it works! Here's the code I used: (client.c)

#include <stdio.h>

#include "dllexport.h"

int main()
{
   // printf() displays the string inside quotation
   printf("Hello, World! %d", test());
   return 0;
}

compiled using:

gcc client.c -g -o client.exe -L. -lmydll_s

and this outputs:

Caught
Hello, World! 1

Please help me understand what is happening.

nbfacilioo commented 3 months ago

@kvnnap any Updates here? Facing the same issue with i686-w64-mingw32 (even with sjlj enabled).

64 bit works fine

kvnnap commented 3 months ago

@nbfacilioo This was a while ago. In my case, I ended up avoiding static compilation and linking everything dynamically. I think that the standard library is compiled differently between dynamic and static, example different flags may be used. I suspect that potential structures differ between these two versions and end up being incompatible. This is all speculation based on intuition as I don't have time to get into it right now. Sorry I can't offer better help