Microsoft Developer Network > Forums Home > Visual Studio Express Editions Forums > Visual C++ Express Edition > Problem "Access violation" with virtual destructor for objects created in DLL
Ask a questionAsk a question
 

AnswerProblem "Access violation" with virtual destructor for objects created in DLL

  • Monday, January 07, 2008 11:39 AMhellomaigue Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello,

     

    I'm facing a problem of access violation when deleting an object created in a shared module (DLL). The problem is illustrated in the code below. Basically, the situation is the following. I have a DLL that defines a class hierarchy with virtual destructor. This DLL can load (LoadLibrary) plugins dynamically (plugins are DLL) and the plugin is expected to create some objects of the classes defined in the main DLL. To implement plugin auto-unload, deleting the object created by the plugin is expected to unload (FreeLibrary) the plugin from memory.

     

    Now the problem is that because of the virtual destructor and the fact that the object is created in the plugin, the MSVC compiler generates some "scalar deleting destructor" code that is executed in the plugin context. This means that when deleting the object, the call stack will contain a frame in the plugin address space corresponding to this auto-generated "scalar deleting destructor". However, as the object destructor unload the plugin from memory, this frame becomes invalid (because the plugin code has been unmapped from memory). This leads to an access violation when unwinding the call stack.

     

    Does anybody know what would be the correct way to handle this? Is there a way to avoid MSVC to generate this "scalar deleting destructor" code in the plugin context?

     

    Thanks.

     

    testdll.h

    #ifndef __testdll_h__
    #define __testdll_h__

     

    #include <string>
    #include <windows.h>

    #ifdef TESTDLL_BUILD
    # define TESTDLL_API __declspec(dllexport)
    #else
    # define TESTDLL_API __declspec(dllimport)
    #endif

     

    class TESTDLL_API A
    {
    public:
     A (void);
     virtual ~A (void);
    };

     

    class TESTDLL_API B : public A
    {
    public:
     B (HMODULE mod);
     ~B (void);

    private:
     HMODULE mod;
    };

     

    typedef A* (* A_builder) (HMODULE);

     

    TESTDLL_API A* make_A_from (const std::string& lib);

     

    #endif

     

     

     

    testdll.cc

    #include "testdll.h"

     

    #include <iostream>
    #include <windows.h>

     

    A::A (void)
    {
     std::cout << "A::A()" << std::endl;
    }

     

    A::~A (void)
    {
     std::cout << "A::~A()" << std::endl;
    }

     

    B::B (HMODULE hmod)
     : mod (hmod)
    {
     std::cout << "B::B(" << (void*)hmod << ")" << std::endl;
    }

     

    B::~B (void)
    {
     std::cout << "B::~B()" << std::endl;
     if (mod)
      FreeLibrary (mod);
    }

     

    A* make_A_from (const std::string& lib)
    {
     HMODULE mod = LoadLibrary (lib.c_str ());
     A* retval = 0;

     if (mod)
     {
      A_builder ab = reinterpret_cast (GetProcAddress (mod, "make_A"));
      if (ab)
       retval = ab (mod);
     }
     return retval;
    }

     

     

    testoct.cc

    #include "testdll.h"

     

    extern "C" __declspec(dllexport) A* make_A (HMODULE mod)
    {
     B* retval = new B (mod);
     return retval;
    }

     

     

    testapp.cc

    #include "testdll.h"
    #include <iostream>

     

    int main (int argc, char **argv)
    {
     std::cout << "making A from testoct.oct" << std::endl;

     A* a = make_A_from ("testoct.oct");
     if (a)
     {
      std::cout << "A object created" << std::endl;
      std::cout << "deleting A" << std::endl;
      delete a;
      std::cout << "A object deleted" << std::endl;
     }

     return 0;
    }

     

     

     

    Makefile

    all: testdll.dll testoct.oct testapp.exe

     

    testdll.dll: testdll.obj
     cl /Zi /LD /Fe$@ testdll.obj user32.lib kernel32.lib

     

    testdll.obj: testdll.cc
     cl /Zi /EHsc /D_DLL /D_MT /DTESTDLL_BUILD /MD /Fo$@ /c testdll.cc

     

    testoct.oct: testoct.obj
     cl /Zi /LD /Fe$@ testoct.obj user32.lib kernel32.lib testdll.lib

     

    testoct.obj: testoct.cc
     cl /Zi /EHsc /D_DLL /D_MT /MD /Fo$@ /c testoct.cc

     

    testapp.exe: testapp.obj
     cl /Zi /Fe$@ testapp.obj user32.lib kernel32.lib testdll.lib

     

    testapp.obj:

     testapp.cccl /Zi /EHsc /MD /Fo$@ /c testapp.cc

     

    clean:
     del /q *.dll *.oct *.exp *.lib *.exe *.ilk *.obj *.pdb *.manifest *.suo

     

     

All Replies

  • Monday, January 07, 2008 11:54 AMeinaros Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Well, the plugin *is* unloading itself in a plugin-kept dtor, so there's no wonder it crashes. Can't you simply unload the dll in whatever loads the plugin in the firstplace?
  • Monday, January 07, 2008 12:59 PMhellomaigue Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     einaros wrote:
    Well, the plugin *is* unloading itself in a plugin-kept dtor, so there's no wonder it crashes. Can't you simply unload the dll in whatever loads the plugin in the firstplace?

     

    I don't agree that the plugin is unloading itself. All the code (ctor and dtor) for my classes is contained in testdll.dll. What the plugin is doing is simply creating an object of the class B; I don't expect any code of class B to be part of the plugin module. However, MSVC still attaches to my B object some code executed in the plugin context. This means that any object created by a dynamic module, whatever the class (provided it has a virtual dtor) and wherever the implementation code is located, must be deleted before unloading the module. This kind of limitation seems to be MSVC-specific.

  • Monday, January 07, 2008 1:55 PMeinaros Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    No, you're right. I only glanced briefly, and missed the filenames of the two generated dlls. I'll have a closer look when I get off work.
  • Wednesday, January 09, 2008 10:56 AMhellomaigue Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer