Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 10:48
Оценка:
Что я упустил?
MSVS 2005.

Есть dll.

Library.h

class Library
{
public:
    Library();
    virtual bool doAction();
private:
    std::string someData_;
};


Library.cpp



Library::Library():
    someData_("DATA")
{
    std::cout<<"Library ctor"<<std::endl;
}

bool Library::doAction()
{
    std::cout<<"Library::doAction() ..."<<std::endl;
    std::cout<<"Library::doAction() throw..."<<std::endl;
    throw std::exception("EX REASON");
    return false;
}

//////////////////////////////////////////////////////////////////////////
/// The add-in singleton.
static Library* g_lib = 0;
/// The initialization flag.
static bool g_isInitialised = false;
//////////////////////////////////////////////////////////////////////////
/// Performs one time initialization.
void init()
{
  if(!g_isInitialised)
  {    
    g_isInitialised = true;
  }
}

//////////////////////////////////////////////////////////////////////////
/// The Factory method.
extern "C" __declspec(dllexport) Library* getInstance()
{
  init();

  if(!g_lib)
  {
    g_lib = new Library();
  }

  assert(g_lib);

  return static_cast<Library*>(g_lib);
}

//////////////////////////////////////////////////////////////////////////
/// Release method.
extern "C" __declspec(dllexport) void release()
{
  delete g_lib;
  g_lib = 0;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    break;
  case DLL_THREAD_ATTACH:
    break;
  case DLL_THREAD_DETACH:
    break;
  case DLL_PROCESS_DETACH:
    release();
    break;
  }
  return TRUE;
}


Есть вызывающее ёё приложение



#include "../Library/Library.h"
#include <iostream>

typedef Library* (*LibFactoryPtr)();
typedef void (*ReleasePtr)(); 

class Loader
{
public:
    Loader():lib_(0)
    {
        std::cout<<"Loader .ctor"<<std::endl;
        LibFactoryPtr getInstanceProc(0);
        std::string name("../debug/Library.dll");
        hinstLib_ = LoadLibrary(name.c_str()); 

        // If the handle is valid, try to get the function address.
        if(hinstLib_ == NULL) 
            throw std::exception("Error loading DLL ", GetLastError());

        getInstanceProc = (LibFactoryPtr)GetProcAddress(hinstLib_, "getInstance"); 

        if(getInstanceProc == NULL) 
            throw std::exception("Error calling function 'getInstance' from DLL ", GetLastError());

        lib_ = (getInstanceProc)();
        if (lib_ == NULL)
            throw std::exception("NULL was returned by function 'getInstance' from DLL", GetLastError());
    }

    bool unload()
    {
        std::cout<<"Loader::unload()"<<std::endl;
        ReleasePtr releaseProc = (ReleasePtr) GetProcAddress(hinstLib_, "release"); 
        if (releaseProc != NULL)
        {
            (releaseProc)();
        }
        std::cout<<"FreeLibrary()..."<<std::endl;
        // Free the DLL module.
        FreeLibrary(hinstLib_);
        return true;
    }
    Library* get()
    {
        return lib_;
    }
private:
    Library* lib_;
    HINSTANCE hinstLib_;
};
Loader loader;

class Dummy
{
public:
    Dummy()
    {
        std::cout<<"Dummy .ctor"<<std::endl;
    }
    bool go(Library* lib)
    {
        std::cout<<"Dummy::go()"<<std::endl;
        try
        {
            lib->doAction();
        }
        catch(const std::exception& ex)
        {
            std::cout<<"Exception occured..."<<std::endl;
            std::cout<<ex.what()<<std::endl;
            loader.unload();
            std::cout<<"Rethrowing..."<<std::endl;
            throw;
        }
        return false;
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        Library* lib = loader.get();
        Dummy dumb;
        dumb.go(lib);
    }
    catch(const std::exception& ex)
    {
        std::cout<<"Dude...we f*cked up...["<<ex.what()<<"]"<<std::endl;
        return 1;
    }
    return 0;
}


dll бросает исключение.
Его ловит Dummy::go() и в catch выгружает dll (в реальном приложении выгрузка происходит в другом потоке ниже по стеку,но результат тот же).
Из Dummy::go() делается попытка пробросить исключение дальше и получается AV.

call stack

msvcr80d.dll!FindHandler(EHExceptionRecord * pExcept=0x0012f8c4, EHRegistrationNode * pRN=0x0012ff5c, _CONTEXT * pContext=0x0012f8e4, void * pDC=0x0012f898, const _s_FuncInfo * pFuncInfo=0x00419e7c, unsigned char recursive=0, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000) Line 740 + 0x6 bytes C++
msvcr80d.dll!__InternalCxxFrameHandler(EHExceptionRecord * pExcept=0x0012f8c4, EHRegistrationNode * pRN=0x0012ff5c, _CONTEXT * pContext=0x0012f8e4, void * pDC=0x0012f898, const _s_FuncInfo * pFuncInfo=0x00419e7c, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000, unsigned char recursive=0) Line 524 + 0x25 bytes C++
msvcr80d.dll!__CxxFrameHandler3(EHExceptionRecord * pExcept=0x7c9032a8, EHRegistrationNode * pRN=0x0012f8c4, void * pContext=0x0012ff5c, void * pDC=0x0012f8e4) Line 365 + 0x1f bytes C++
ntdll.dll!_ZwQueryInformationProcess@20() + 0xc bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!ExecuteHandler2@20() + 0x26 bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!_KiUserExceptionDispatcher@8() + 0xe bytes
kernel32.dll!_RaiseException@16() + 0x52 bytes
msvcr80d.dll!_CxxThrowException(void * pExceptionObject=0x0012fc64, const _s__ThrowInfo * pThrowInfo=0x10004bd4) Line 161 C++
10001170()
> Application.exe!Dummy::go(Library * lib=0x00367360) Line 71 + 0xe bytes C++
Application.exe!main(int argc=1, char * * argv=0x003671d0) Line 94 C++
Application.exe!__tmainCRTStartup() Line 597 + 0x19 bytes C
Application.exe!mainCRTStartup() Line 414 C
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes


output

Loader .ctor
Library ctor
Dummy .ctor
Dummy::go()
Library::doAction() ...
Library::doAction() throw...
Exception occured...
EX REASON
Loader::unload()
FreeLibrary()...
Rethrowing...

и AV

Unhandled exception at 0x1024c61c (msvcr80d.dll) in Application.exe: 0xC0000005: Access violation reading location 0x10004be0.


Is this expected behavior ?

PS поведение сохраняется если ловить не const std::exception& , а просто std::exception.
И даже если сделать
std::exception e = ex;
std::cout<<"Rethrowing..."<<std::endl;
throw e;
Re: Exception from dll -> dll unload -> AV
От: ononim  
Дата: 27.01.10 11:01
Оценка: +1
exception кидать в одном и ловить в другом модуле такая же bad practice как и память выделять в одном и освобождать в другом дефолтовым (а значит неизвестно каким в общем случае) аллокатором
Как много веселых ребят, и все делают велосипед...
Re: Exception from dll -> dll unload -> AV
От: Centaur Россия  
Дата: 27.01.10 11:05
Оценка: -5
Здравствуйте, blackhearted, Вы писали:

B>Что я упустил?


Классы вообще и исключения в частности нельзя использовать через границу DLL.
Re[2]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 11:08
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Здравствуйте, blackhearted, Вы писали:


B>>Что я упустил?


C>Классы вообще и исключения в частности нельзя использовать через границу DLL.


т.е. нужно редизайнить ?
Какая best practice в таких случаях (обработка исключений брошенных в dll)?
Re[2]: Exception from dll -> dll unload -> AV
От: Тот кто сидит в пруду Россия  
Дата: 27.01.10 11:17
Оценка: +1
Здравствуйте, Centaur, Вы писали:

B>>Что я упустил?


C>Классы вообще и исключения в частности нельзя использовать через границу DLL.


Бред. Правильно писать "Классы вообще и исключения в частности нельзя использовать через границу DLL, если к тому нет веских причин". Часто такие причины есть, и польза от использования классов и исключений через границы dll многократно перевешивает вред.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: Exception from dll -> dll unload -> AV
От: Кодт Россия  
Дата: 27.01.10 11:59
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Классы вообще и исключения в частности нельзя использовать через границу DLL.


Можно.

В данном случае ошибка, скорее всего, произошла из-за того, что у DLL и EXE разные CRT.
Как следствие,
— нарушение ODR в реализации std::exception (в частности, vtable); попытка вызвать virtual what() и virtual ~exception() из уже несуществующей таблицы
— два менеджера кучи; строка-параметр исключения была создана одним malloc'ом, а освобождается другим

Решение очевидно: компилировать оба проекта с /MD или /MDd.
Перекуём баги на фичи!
Re[3]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 12:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>В данном случае ошибка, скорее всего, произошла из-за того, что у DLL и EXE разные CRT.

К>Как следствие,
К>- нарушение ODR в реализации std::exception (в частности, vtable); попытка вызвать virtual what() и virtual ~exception() из уже несуществующей таблицы
К>- два менеджера кучи; строка-параметр исключения была создана одним malloc'ом, а освобождается другим

К>Решение очевидно: компилировать оба проекта с /MD или /MDd.


Оба откомпилированы с MDd.
Re[2]: Exception from dll -> dll unload -> AV
От: alsemm Россия  
Дата: 27.01.10 12:41
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Здравствуйте, blackhearted, Вы писали:


B>>Что я упустил?


C>Классы вообще и исключения в частности нельзя использовать через границу DLL.

— классы через границы DLL использовать можно и нужно. Не совсем классы конечно, интерфейсы. Пример — COM.
Re: Exception from dll -> dll unload -> AV
От: alsemm Россия  
Дата: 27.01.10 12:54
Оценка:
Здравствуйте, blackhearted, Вы писали:

B>dll бросает исключение.

B>Его ловит Dummy::go() и в catch выгружает dll (в реальном приложении выгрузка происходит в другом потоке ниже по стеку,но результат тот же).
B>Из Dummy::go() делается попытка пробросить исключение дальше и получается AV.
Выгружать dll из которой вылетело исключение перед тем как пробрасывать пойманное исключение дальше — это не очень хорошая идея.
Я бы так переписал:

class exception_wrapper: std::exception
{
    const std::exception& wrapee_;
public:
    explicit exception_wrapper(const std::exception& wrapee): wrapee_(wrapee) {}
    virtual ~exception_wrapper() { loader.unload(); }
};

try
{
    lib->doAction();
}
catch(const std::exception& ex)
{
    std::cout<<"Exception occured..."<<std::endl;
    std::cout<<ex.what()<<std::endl;
    std::cout<<"Rethrowing..."<<std::endl;
    throw exception_wrapper(ex);
}
return false;
Re[4]: Exception from dll -> dll unload -> AV
От: Кодт Россия  
Дата: 27.01.10 12:58
Оценка:
Здравствуйте, blackhearted, Вы писали:

B>Оба откомпилированы с MDd.


Тогда надо под отладчиком запустить и посмотреть в дизассемблере, что именно отстреливается.
Перекуём баги на фичи!
Re: Exception from dll -> dll unload -> AV
От: Fanto  
Дата: 27.01.10 13:11
Оценка:
Здравствуйте, blackhearted, Вы писали:

B>PS поведение сохраняется если ловить не const std::exception& , а просто std::exception.

B>И даже если сделать
B>
B>std::exception e = ex;
B>std::cout<<"Rethrowing..."<<std::endl;
B>throw e;
B>


А вот так вот пробовали?

std::exception e = ex;
std::cout<<"Rethrowing..."<<std::endl;
loader.unload();
throw e;
Re[5]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 13:15
Оценка:
Здравствуйте, Кодт, Вы писали:


К>Тогда надо под отладчиком запустить и посмотреть в дизассемблере, что именно отстреливается.



try
{
00411851 mov dword ptr [ebp-4],0
lib->doAction();
00411858 mov eax,dword ptr [ebp+8]
0041185B mov edx,dword ptr [eax]
0041185D mov esi,esp
0041185F mov ecx,dword ptr [ebp+8]
00411862 mov eax,dword ptr [edx]
00411864 call eax
00411866 cmp esi,esp ; падает тут
00411868 call @ILT+465(__RTC_CheckEsp) (4111D6h)
}
catch(std::exception ex)
0041186D jmp __catch$?go@Dummy@@QAE_NPAVLibrary@@@Z$0+0C9h (41193Bh)
__catch$?go@Dummy@@QAE_NPAVLibrary@@@Z$0:
00411872 mov byte ptr [ebp-4],2
{
std::cout<<"Exception occured..."<<std::endl;
00411876 mov esi,esp
00411878 mov eax,dword ptr [__imp_std::endl (41C358h)]
0041187D push eax
0041187E push offset string "Exception occured..." (41893Ch)
00411883 mov ecx,dword ptr [__imp_std::cout (41C354h)]
00411889 push ecx
0041188A call std::operator<<<std::char_traits<char> > (411181h)
0041188F add esp,8
00411892 mov ecx,eax
00411894 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41C350h)]
0041189A cmp esi,esp
0041189C call @ILT+465(__RTC_CheckEsp) (4111D6h)
std::cout<<ex.what()<<std::endl;
004118A1 mov esi,esp
004118A3 mov eax,dword ptr [__imp_std::endl (41C358h)]
004118A8 push eax
004118A9 mov edi,esp
004118AB lea ecx,[ex]
004118AE call dword ptr [__imp_std::exception::what (41C448h)]
004118B4 cmp edi,esp
004118B6 call @ILT+465(__RTC_CheckEsp) (4111D6h)
004118BB push eax
004118BC mov ecx,dword ptr [__imp_std::cout (41C354h)]
004118C2 push ecx
004118C3 call std::operator<<<std::char_traits<char> > (411181h)
004118C8 add esp,8
004118CB mov ecx,eax
004118CD call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41C350h)]
004118D3 cmp esi,esp
004118D5 call @ILT+465(__RTC_CheckEsp) (4111D6h)
loader.unload();
004118DA mov ecx,offset loader (41B1A0h)
004118DF call Loader::unload (4110C8h)
std::cout<<"Rethrowing..."<<std::endl;
004118E4 mov esi,esp
004118E6 mov eax,dword ptr [__imp_std::endl (41C358h)]
004118EB push eax
004118EC push offset string "Rethrowing..." (41892Ch)
004118F1 mov ecx,dword ptr [__imp_std::cout (41C354h)]
004118F7 push ecx
004118F8 call std::operator<<<std::char_traits<char> > (411181h)
004118FD add esp,8
00411900 mov ecx,eax
00411902 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41C350h)]
00411908 cmp esi,esp
0041190A call @ILT+465(__RTC_CheckEsp) (4111D6h)
throw;
0041190F push 0
00411911 push 0
00411913 call @ILT+350(__CxxThrowException@8) (411163h)
}


стэк

msvcr80d.dll!FindHandler(EHExceptionRecord * pExcept=0x0012f8bc, EHRegistrationNode * pRN=0x0012ff5c, _CONTEXT * pContext=0x0012f8dc, void * pDC=0x0012f890, const _s_FuncInfo * pFuncInfo=0x00419e7c, unsigned char recursive=0, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000) Line 740 + 0x6 bytes C++
msvcr80d.dll!__InternalCxxFrameHandler(EHExceptionRecord * pExcept=0x0012f8bc, EHRegistrationNode * pRN=0x0012ff5c, _CONTEXT * pContext=0x0012f8dc, void * pDC=0x0012f890, const _s_FuncInfo * pFuncInfo=0x00419e7c, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000, unsigned char recursive=0) Line 524 + 0x25 bytes C++
msvcr80d.dll!__CxxFrameHandler3(EHExceptionRecord * pExcept=0x7c9032a8, EHRegistrationNode * pRN=0x0012f8bc, void * pContext=0x0012ff5c, void * pDC=0x0012f8dc) Line 365 + 0x1f bytes C++
ntdll.dll!_ZwQueryInformationProcess@20() + 0xc bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!ExecuteHandler2@20() + 0x26 bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!_KiUserExceptionDispatcher@8() + 0xe bytes
kernel32.dll!_RaiseException@16() + 0x52 bytes
msvcr80d.dll!_CxxThrowException(void * pExceptionObject=0x0012fc5c, const _s__ThrowInfo * pThrowInfo=0x10004bd4) Line 161 C++
10001170()
> Application.exe!Dummy::go(Library * lib=0x00367360) Line 71 + 0xe bytes C++
Application.exe!main(int argc=1, char * * argv=0x003671d0) Line 94 C++
Application.exe!__tmainCRTStartup() Line 597 + 0x19 bytes C
Application.exe!mainCRTStartup() Line 414 C
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes


Re[2]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 13:17
Оценка:
Здравствуйте, alsemm, Вы писали:

A>Выгружать dll из которой вылетело исключение перед тем как пробрасывать пойманное исключение дальше — это не очень хорошая идея.


В примере приведен минимальный код
На самом деле всё гораздо сложнее и либа выгружается из другого потока
Re[2]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 13:19
Оценка:
Здравствуйте, Fanto, Вы писали:

F>А вот так вот пробовали?


F>
F>std::exception e = ex;
F>std::cout<<"Rethrowing..."<<std::endl;
F>loader.unload();
F>throw e;
F>


Конечно
То же самое.
Re[6]: Exception from dll -> dll unload -> AV
От: Тот кто сидит в пруду Россия  
Дата: 27.01.10 13:23
Оценка:
Здравствуйте, blackhearted, Вы писали:

B>Здравствуйте, Кодт, Вы писали:



К>>Тогда надо под отладчиком запустить и посмотреть в дизассемблере, что именно отстреливается.



B>[q]

B> try
B> {
B>00411851 mov dword ptr [ebp-4],0
lib->>doAction();
B>00411858 mov eax,dword ptr [ebp+8]
B>0041185B mov edx,dword ptr [eax]
B>0041185D mov esi,esp
B>0041185F mov ecx,dword ptr [ebp+8]
B>00411862 mov eax,dword ptr [edx]
B>00411864 call eax
B>00411866 cmp esi,esp ; падает тут
B>00411868 call @ILT+465(__RTC_CheckEsp) (4111D6h)


Так не бывает, в указанной строке нечему падать. Можно предположить, что на самом деле упало на call eax. eax чему равен — не 0x10004be0 (из первого сообщения) случаем? У lib __vptr или как его там не порушен ли уже?
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Exception from dll -> dll unload -> AV
От: gear nuke  
Дата: 27.01.10 13:25
Оценка: 2 (1)
Здравствуйте, blackhearted, Вы писали:

B>dll бросает исключение.

B>Его ловит Dummy::go() и в catch выгружает dll (в реальном приложении выгрузка происходит в другом потоке ниже по стеку,но результат тот же).

Можно посмотреть на реальный вариант, включая call-stack?

То, что происходит сейчас, понятно:
B>

B>Unhandled exception at 0x1024c61c (msvcr80d.dll) in Application.exe: 0xC0000005: Access violation reading location 0x10004be0.

Падает msvcr80d.dll!FindHandler при попытке распарсить структуру _s__ThrowInfo. Она находится в dll, которая на этот момент выгружена.

Этот контекст был при первом throw std::exception("EX REASON"); —
B>

B> msvcr80d.dll!_CxxThrowException(void * pExceptionObject=0x0012fc64, const _s__ThrowInfo * pThrowInfo=0x10004bd4) Line 161 C++
B> 10001170()

throw; перевыбрасывая исключение, восстанавливает первоначальный контекст, но dll уже нет.

Выгружать dll придётся где-то позже Dummy::go(). Другой тред может не дождаться раскрутки при брошенном исключении.

B>PS поведение сохраняется если ловить не const std::exception& , а просто std::exception.


Что бы отделить влияние диспетчера исключений от разных менеджеров куч, можно пробовать бросать например int.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[4]: Exception from dll -> dll unload -> AV
От: Kh_Oleg  
Дата: 27.01.10 13:26
Оценка:
Здравствуйте, blackhearted, Вы писали:

B>Здравствуйте, Кодт, Вы писали:


К>>В данном случае ошибка, скорее всего, произошла из-за того, что у DLL и EXE разные CRT.

К>>Как следствие,
К>>- нарушение ODR в реализации std::exception (в частности, vtable); попытка вызвать virtual what() и virtual ~exception() из уже несуществующей таблицы
К>>- два менеджера кучи; строка-параметр исключения была создана одним malloc'ом, а освобождается другим

К>>Решение очевидно: компилировать оба проекта с /MD или /MDd.


B>Оба откомпилированы с MDd.

Угу. Позволю сделать предположение, что STL'ные классы не являются частью CRT, поэтому опция MD(d) — что мертвому припарка: таблица виртуальных методов std::exception, порожденной в DLL физически находится в этой (выгруженной) DLL, отсюда и свал при попытке обратиться к виртуальному методу. Правила работы с менеджером памяти (хотя и являются здравым советом) в данном конкретном случае ни при чем.
Попробуй не пробрасывать существующее исключение (throw; ), а кинуть его копию (throw ex; )

А вообще, корректное использование всех фич С++ через границы DLL возможно лишь при соблюдении одного неприятного условия — оба модуля должны быть откомпилированными одним и тем же компилятором. Не разными версиями одного и того же, а строго одним и тем же.
Re[5]: Exception from dll -> dll unload -> AV
От: gear nuke  
Дата: 27.01.10 13:28
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Тогда надо под отладчиком запустить и посмотреть в дизассемблере, что именно отстреливается.


Боюсь, это придётся делать из WinDbg, MS позаботились что бы отладчик Студии не заходил в диспетчер исключений (для этого там функции _NLG_Notify и т.п.)
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[5]: Exception from dll -> dll unload -> AV
От: ononim  
Дата: 27.01.10 13:32
Оценка:
K_O>А вообще, корректное использование всех фич С++ через границы DLL возможно лишь при соблюдении одного неприятного условия — оба модуля должны быть откомпилированными одним и тем же компилятором. Не разными версиями одного и того же, а строго одним и тем же.
Кроме компилятора еще бывают разные версии STL, BOOST
Кроме того бывают например такие STL, которые замещают стандартный аллокатор своим, который создает свою кучу, в каждом модуле свою...
Кроме того немного непонятно зачем делать проект состоящий из кучи разных длл, если условием нормальной работы которого является то, чтобы они были скомпилены все вместе одним компилятором и с одним и тем же набором разных либ, то есть фактически — чтоб это былоа единая компиляция. Не проще ли в таком случае сделать монолитный модуль, к чему эти длл?
Как много веселых ребят, и все делают велосипед...
Re[5]: Exception from dll -> dll unload -> AV
От: blackhearted Украина  
Дата: 27.01.10 13:39
Оценка:
Здравствуйте, Kh_Oleg, Вы писали:

K_O>Угу. Позволю сделать предположение, что STL'ные классы не являются частью CRT, поэтому опция MD(d) — что мертвому припарка: таблица виртуальных методов std::exception, порожденной в DLL физически находится в этой (выгруженной) DLL, отсюда и свал при попытке обратиться к виртуальному методу. Правила работы с менеджером памяти (хотя и являются здравым советом) в данном конкретном случае ни при чем.

K_O>Попробуй не пробрасывать существующее исключение (throw; ), а кинуть его копию (throw ex; )

K_O>А вообще, корректное использование всех фич С++ через границы DLL возможно лишь при соблюдении одного неприятного условия — оба модуля должны быть откомпилированными одним и тем же компилятором. Не разными версиями одного и того же, а строго одним и тем же.


Они откомпилированы строго одним и темже компилятором с разницей в 10 секунд


throw ex;


Те же яйца.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.