如何构建C++;捕捉所有异常的Dll包装器? 就像标题所说的,我们正在寻找一种方法来捕捉来自C++代码的所有异常,并将其封装在DLL中。通过这种方式,我们可以保护使用此dll的应用程序的安全,使其不受此dll中发生的任何错误的影响 但是,在Windows下C++似乎是不可能的。p>
例如:如何构建C++;捕捉所有异常的Dll包装器? 就像标题所说的,我们正在寻找一种方法来捕捉来自C++代码的所有异常,并将其封装在DLL中。通过这种方式,我们可以保护使用此dll的应用程序的安全,使其不受此dll中发生的任何错误的影响 但是,在Windows下C++似乎是不可能的。p>,c++,winapi,exception,visual-c++,C++,Winapi,Exception,Visual C++,例如: void function() { try { std::list<int>::iterator fd_it; fd_it++; } catch(...) {} } void函数() { 尝试 { std::list::迭代器fd_it; fd_it++; }捕获(…){} } 例外的情况不被标准C++尝试/ catch块捕获,也不被任何代码SE>翻译器函数所设置。相反,DLL崩溃,使
void function()
{
try
{
std::list<int>::iterator fd_it;
fd_it++;
} catch(...) {}
}
void函数()
{
尝试
{
std::list::迭代器fd_it;
fd_it++;
}捕获(…){}
}
例外的情况不被标准C++尝试/ catch块捕获,也不被任何代码SE>翻译器函数所设置。相反,DLL崩溃,使用DLL的程序中止。我们使用Visual C++ 2005编写了选项/SHA.有没有人知道,在C++和Win32中有可能捕捉到这些问题并生成ROCKSOLL DLL包装器吗?< /P> < P>在标准的LabBar容器上增加迭代器将不会抛出C++异常。在Windows上,C++有2种不同的异常类型:C++和SEH异常。p> SEH是一种仅限windows的异常形式(有点类似于UNIX中的信号)。这更像是一个系统级的异常。对于无效指针访问、对齐问题等操作,将抛出它们
<>如果你想捕捉Windows上C++应用程序所能抛出的所有异常,你需要同时捕获这两个异常。幸运的是,有一种方法可以混合使用C++和SEH异常。我最近写了一篇关于这方面的详细博客,它应该会帮助你您看过windows API函数SetUnhandledExceptionFilter吗
我通常在DllMain函数中调用它,并在DLL崩溃时让它生成一个小型转储。但是:(a)我不知道它是否会捕获应用程序异常和DLL异常,以及(b)我不知道是否可以让处理程序以这样的方式返回,以使程序执行能够继续。文档说是的,但我从来没有这样做过。制作一个坚如磐石的DLL包装器的唯一方法是在另一个进程中加载有缺陷的DLL,这样,如果它崩溃了,它就不会让您的主进程崩溃
捕获所有C++异常似乎是合理的,但捕捉所有结构化异常是另一回事。SEH似乎在大部分方面都能帮到您,因为它允许您捕获访问冲突、除以零异常等
但是,如果错误的DLL碰巧接触到另一个线程堆栈中的未提交页面,该怎么办?内存访问将出现页面错误,将调用异常处理程序,现在该页面不再是保护页面。当该线程需要增加堆栈时,它将获得访问冲突,进程将崩溃。(请更详细地描述此案例。) 另一个可能的问题是:错误的DLL在保存同步对象时崩溃,但您使用SEH捕获异常。如果您的进程试图获取相同的同步对象,那么它会死锁而不是崩溃。共享同步对象可能是C运行时或操作系统的一部分:如果buggy DLL 1加载buggy DLL 2,当buggy DLL 1持有加载程序锁时,它在其DllMain()
中崩溃,该怎么办?您的进程下次加载DLL时会死锁吗
有关这(以及类似问题的函数,如IsBadReadPtr()
)为何误用SEH的更多信息,请参见:
- 拉里·奥斯特曼的博客:
- 拉里·奥斯特曼的博客:
- 拉里·奥斯特曼的博客:
- 新旧事物:
当然,这是特定于特定代码的。其他人则提出了更一般的建议。然而,我发现很多人实际上更喜欢捕捉异常而不是修复逻辑错误,这是完全不能接受的。下面的代码取自IDE。它将捕获所有Windows生成的异常: 步骤#1:定义异常筛选函数
DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
{
//-- we handle all exceptions
DWORD dwResult = EXCEPTION_EXECUTE_HANDLER;
switch (dwException)
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_BREAKPOINT:
dwResult = EXCEPTION_EXECUTE_HANDLER;
break;
}
return dwResult;
}
第2步:将代码包装为“尝试”和“尝试”,如下所示除外:
__try
{
// call your dll entry point here
}
__except(ExceptionFilter(GetExceptionInformation(),
GetExceptionCode()))
{
//-- display the fatal error message
MessageBox(0, "An unexpected error was caught here!",
"Unexpected Error", MB_OK);
}
捕捉到异常(特别是SEH异常)后,您将做什么 实际上,您不能对流程的状态做出任何假设,实际上您唯一的选择是(可选地)转储核心并退出
从长远来看,任何尝试和操作都绝对会给您带来问题。康拉德·鲁道夫:当然,这段代码包含一个“逻辑错误”,它是为了说明可能发生的问题。就像那个人说的,他希望能够保护他的dll免受任何可能的错误。你不认为这是一个合理的问题吗?听说过供应商的产品。我们中的一些人生活在现实世界中,生活在现实问题中。解决其他人的问题是不可能的它会抛出一个结构化异常,这是Microsoft编译器的事情。对于那些你能捕捉到的除数为零,内存访问不良等等。。。语义不同于C++异常,这是标准C++中的未定义行为,当然我并不反对。只是指出在VC++中,它实际上会抛出一些可以被捕获的东西(…)。但这不是标准C++,任何异常都不等于错误。这只是个例外。它们发生了,这就是它们存在的原因。这是否明智的原则将是一个遥远的话题。(不是风扇,打开第二个程序流路径)。未捕获的异常可能导致错误。如果没有其他合适的位置来捕获异常,那么可以在最高级别捕获它。只要捕获到异常,这是完全可以接受的。@thewhiteambit我不是说一般情况,我是说OP的特定代码。我在这里看不到特定代码。也许是第三方DLL,他不能