c – 捕获dll异常后访问冲突
作者:互联网
我必须在运行时动态加载模块作为dll,因为它们不是提前知道的,只是它们符合类接口.我注意到的是,在我捕获到dll抛出的异常(在主线程的主程序中)之后,调用了正确的析构函数并且模块被销毁并且dll被卸载,但是然后作为catch块末尾的}当逐步步进时,Visual Studio C调试器到达,我得到另一个异常,它使程序崩溃
xxxxx.exe中0x68ad2377(msvcr90d.dll)的第一次机会异常:0xC0000005:访问冲突读取位置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;
}
解决方法:
要记住的是C运行时库的每个副本都有自己的状态.如果SomeSpecificModule.dll静态链接到C运行时库,则可能会发生此类问题.如果是这种情况,请尝试链接到C版本的C运行时库的DLL版本.您还必须确保SomeSpecificModule.dll的编译和链接方式与主模块完全相同.
你提到DLL被卸载并且调用了正确的析构函数,听起来你的真实程序比你发布的样本还要多得多.如果您在try块中卸载了SomeSpecificModule.dll,那么您已经卸载了SomeSpecificModule :: Foo()的异常记录,我想这就是你在msvcr90d.dll崩溃的原因!__ DestructExceptionObject(EHExceptionRecord * …
但是,通常在DLL边界上抛出异常会造成麻烦.如果您正在抛出非POD对象,则可能会遇到由不同堆,不同编译器设置,STL版本中的不同C运行时库分配的内存问题…您明白了.
更改代码,这样就不会抛出DLL边界.有一天,你团队中的某个人改变了编译器设置或第三方标题#define已经改变,你的程序开始崩溃,你将很难找到根本原因.
无论如何,没有看到真正的代码,我只是想猜测可能会出现什么问题.希望能帮助到你.
标签:access-violation,c,exception,virtual,dll 来源: https://codeday.me/bug/20190724/1520104.html