jmeubank / tdm-gcc

TDM-GCC is a cleverly disguised GCC compiler for Windows!
https://jmeubank.github.io/tdm-gcc/
584 stars 49 forks source link

Application crashed with dynamic link DLL which use 'new' operator and compiled by TDM-GCC 10.3.0. #45

Open HopeForWholeVillage opened 2 years ago

HopeForWholeVillage commented 2 years ago

I have an application which compiled by TDM-GCC 10.3.0, and it use LoadLibrary to link a DLL. After the application run, it will crash. When debug it, cause SIGSEGV signal. In DLL, there is a function contains new operator, but this function never be called.

My OS is windows 10 (64 bits).

The code of application in 'main.cpp' shows below:

#include <windows.h>

#include "dllx.hpp"

void test()
{
    HMODULE hDll = ::LoadLibrary("libsay.dll");
    if (hDll)
    {
        /*PFNGetSay pfnSay = (PFNGetSay)GetProcAddress(hDll, "get_say");
        PFNFreeSay pfnFree = (PFNFreeSay)GetProcAddress(hDll, "free_say");
        if (pfnSay && pfnFree)
        {
            ISay* psay = (*pfnSay)();
            if (psay)
            {
                psay->say();
                (*pfnFree)(psay);
            }
        }*/

        ::FreeLibrary(hDll);
    }
}

int main()
{
    test();
    return 0;
}

And the code of DLL in 'dllx.cpp' :

#include <stdio.h>
#include <windows.h>

#include "dllx.hpp"

class SayImpl : public ISay
{
public:
    virtual void say()
    {
        printf("Hello world ISay!\r\n");
    }
};

extern "C" ISay* DLLEXPORT get_say()
{
    return new SayImpl();
    //return nullptr;
}

extern "C" void DLLEXPORT free_say(ISay* pSay)
{
    if (pSay) delete pSay;
}

extern "C" BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_DETACH)
    {
        printf("DLL_PROCESS_DETACH\r\n");
    }

    return TRUE;
}

The code of file 'dllx.hpp':

#ifndef _DLLX_EXPORT_H_INCLUDED
#define _DLLX_EXPORT_H_INCLUDED

#ifdef __GNUC__
#define DLLEXPORT   __attribute__((dllexport))
#else
#define DLLEXPORT   __declspec(dllexport)
#endif // __GNUC__

class ISay
{
public:
    virtual void say() = 0;
};

typedef ISay* (*PFNGetSay)();
typedef void (*PFNFreeSay)(ISay*);

#endif // !_DLLX_EXPORT_H_INCLUDED

If I commented line ::FreeLibrary(hDll); in application or use line return nullptr; to replace line return new SayImpl(); in DLL, the problem resolved.

Is it a bug of TDM-GCC? How can I use FreeLibrary and new operator?

justanotheranonymoususer commented 2 years ago

Looks like this issue, see my comment for a workaround: https://github.com/jmeubank/tdm-gcc/issues/38#issuecomment-913016367

revelator commented 2 years ago

a little safer way to do it maybe ?

while { atexit( __SHMEM_NAME( cleanup_local_region ) ) == 0 };

must be changed in the patches from _onexit should only run atexit if it can successfully do so i hope.

revelator commented 2 years ago

been a while since i coded last xD forget the above, it also returns 0 on error in the mutex lock so not applicable. i changed the code for the mutex lock to use exit(EXIT_SUCCESS); instead of returning 0.