2

I'm trying to make an inter-compiler compatible class in a dll built with mingw that can be used in a Windows VS application. My issue is, my class crashes the moment it tries to initialize a member variable when a function is called from the VS program. Using the STL or making local variables within the same functions works fine.

Unhandled exception at 0x6BEC19FE (test.dll) in ConsoleApplication2.exe: 0xC0000005: Access violation writing location 0x154EB01E.

Simple demonstration:

The dll code

#include <iostream>

class Tester 
{
public:

    virtual void test() = 0;
};

class TesterImp : public Tester
{
public:
    TesterImp(){}
    ~TesterImp(){}

    virtual void test() { 
        int test = 5; // fine
        m_test = 5; // access violation
    }

private:

    int m_test;

};

    extern "C"
    {
        __declspec (dllexport) Tester* Create()
        {
            return new TesterImp();
        }
    }

Main program that loads the dll and calls the test function:

#include <iostream>
#include <Windows.h> 

class Tester 
{
public:

    virtual void test() = 0;
};

typedef Tester* (*createPtr)();

int main(int argc, const char **argv, char * const *envp) {

  HINSTANCE hGetProcIDDLL = LoadLibraryA("test.dll");

  if (hGetProcIDDLL == NULL) {
    std::cout << "could not load the dynamic library" << std::endl;
    return EXIT_FAILURE;
  }

  createPtr ctr = (createPtr)GetProcAddress(hGetProcIDDLL, "Create");
  if (!ctr) {
    std::cout << "could not locate the function" << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "dll loading success!" << std::endl;

  Tester* testf = ctr();

  std::cout << "Got test class" << std::endl;

  testf->test(); // crash if the member variable is referenced, fine otherwise with local variable initialization or STL use inside the function

  std::cout << "Running dll functions success!" << std::endl;

  return 0;
}

Main program is compiled in debug mode with VS2012 and the dll is built using g++ from mingw -

g++ -shared -o test.dll test.cpp

Could someone explain this behavior for me, please?

Thank you.

user2380227
  • 267
  • 4
  • 14
  • I'd start by ensuring your calling conventions matched up, followed by stepping into `ctr()` with a debugger, which will tell you almost immediately what the issue is. I'm also not entirely clear on where your claim of accessing a dynamic allocated derived class with virtual methods through an abstract base interface qualifies as a POD-*anything* in C++. – WhozCraig May 14 '13 at 05:54
  • `Tester` is not a POD. – Michael Burr May 14 '13 at 06:34
  • I was referring to int m_test as the POD class member. – user2380227 May 14 '13 at 06:43
  • Unfortunately I can't debug that function through VS since mingw doesn't generate the symbols file VS uses for debugging. – user2380227 May 14 '13 at 06:54
  • Well I've tried messing with the calling conventions to no avail, looks like I might need to just write the whole interface as exported C style functions. – user2380227 May 14 '13 at 07:18
  • @user2380227: you might not get symbols, but VS will step through the MinGW DLL function in the disassembly window. The `TesterImp::test()` function is only about 10 lines of assembly so it probably shouldn't be too painful too follow. – Michael Burr May 14 '13 at 07:20
  • @user2380227: what versions of MSVC and MinGW are you using - this seems to work for me with MSVC 2010 and MinGW 4.7.2 – Michael Burr May 14 '13 at 07:37
  • VS 2012 and latest mingw, I'll try it with VS 2010 and see what happens. You compiled this code without any changes? – user2380227 May 14 '13 at 07:45
  • Yes - I compiled without changes. Are you sure that you used the latest MinGW? I was about to post an answer that speculated that you're using a version of MinGW with GCC 4.6.x or eariler. Before 4.7.0, MinGW passed the `this` pointer on the stack - MSVC expects it in `ecx` (which MinGW 4.7.0 and later do). – Michael Burr May 14 '13 at 07:48

1 Answers1

1

You're probably using an older version of MinGW. Up until 4.7.0 (I think), MinGW passed the this pointer on the stack which is different than MSVC's thiscall convention of passing the this pointer in ecx.

Starting with 4.7.0, MinGW uses the same thiscall calling convention as MSVC.

I can also get the example TesterImp::test() function to be called from MSVC successfully by marking both Tester::test() and TesterImp::test() in test.cpp with the __attribute__((thiscall)) attribute. This worked with MinGW 4.6.2, which would cause a crash without the attribute being used.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • You're absolutely right, I just checked the gcc version and it was 4.62 (not sure how that happened, I got the latest package installer from the mingw site). Thank you very much for your time, you've really helped me out! – user2380227 May 14 '13 at 08:24