我必须在运行时将模块作为dlls动态加载,因为它们并不是事先知道的,只是它们符合类接口。我注意到的是,在捕获到dll抛出的异常(在主线程的主程序中)后,将调用正确的析构函数,销毁模块并卸载dll,但是当Visual Studio C++调试器在逐行单步执行时到达catch块末尾的}时,我会得到另一个异常,它会使程序崩溃
xxxxx.exe: 0xC0000005中0x68ad2377 (msvcr90d.dll)处的第一次机会异常:访问冲突读取位置0x02958f14。
如果我启用了对异常进行中断,则对第二个异常进行中断会将位置显示为
msvcr90d.dll!__DestructExceptionObject(EHExceptionRecord * pExcept=0x0017ee4c,unsigned char fThrowNotAllowed=0)行1803 + 0xf字节
但是看起来帧堆栈可能已经损坏了。我搞不懂为什么会抛出这个异常。
我的代码结构的简化版本如下:
一个非常简单的程序结构:
//shared header:
class Module
{
public:
virtual void Foo(void) = 0;
};
//dll:
class SomeSpecificModule : public Module
{
public:
virtual void Foo(void);
};
void SomeSpecificModule::Foo(void)
{
throw 1;
}
extern "C" __declspec(dllexport) Module* GetModule()
{
return new SomeSpecificModule;
}
//program:
typedef ptrGetModule* (*GetModule)();
int main(void)
{
HANDLE hMod = LoadLibrary("SomeSpecificModule.dll");
ptrGetModule GetModule = (ptrGetModule)GetProcAddress(hMod, "GetModule");
try
{
Module *d = GetModule();
d->Foo();
}
catch (...)
{
cout << '!' << endl;
}
return 0;
}发布于 2009-06-09 05:25:49
需要记住的是,C运行时库的每个副本都有自己的状态。如果SomeSpecificModule.dll静态链接到C运行时库,则可能会发生这种问题。如果是这种情况,请尝试使用C运行时库的DLL版本进行链接。您还必须确保SomeSpecificModule.dll的编译和链接方式与主模块完全相同。
你提到了DLL正在被卸载,并且调用了正确的析构函数,听起来你真正的程序比你发布的示例要多得多。如果您在try块中卸载了SomeSpecificModule.dll,那么您已经卸载了SomeSpecificModule::Foo()的异常记录,我猜这就是在msvcr90d.dll!__DestructExceptionObject(EHExceptionRecord * ...处发生崩溃的原因
然而,一般来说,跨DLL边界抛出异常是自找麻烦。如果你抛出非POD对象,你可能会遇到由不同堆中的不同C运行时库分配的内存问题,不同的编译器设置,STL version...you得到了重点。
更改您的代码,这样您就不会抛出DLL边界。有一天,你的团队中有人改变了编译器的设置,或者第三方的头文件#define改变了,你的程序开始崩溃,你将很难找到根本原因。
无论如何,在没有看到真正的代码的情况下,我只是在尝试猜测可能会出错的地方。希望能有所帮助。
发布于 2009-06-09 16:39:28
当DLL引发异常时,需要调用的堆栈展开代码的大部分都在DLL中。如果卸载DLL,如何调用该代码?
不要在动态链接的模块边界上抛出异常。
发布于 2009-06-09 03:38:16
您是否在实际代码中通过值调用异常?在这种情况下,在catch块末尾复制的异常对象的析构函数中可能存在异常。
https://stackoverflow.com/questions/967982
复制相似问题