繁体   English   中英

如何构建一个捕获所有异常的C ++ Dll包装器?

[英]How to build a C++ Dll wrapper that catches all exceptions?

就像标题所说,我们正在寻找一种方法来捕获一段C ++代码中的所有异常,并将其包装在一个DLL中。 这样我们可以屏蔽使用此dll的应用程序,从此dll中发生的任何错误。

但是,在Windows下使用C ++似乎不太可行。

例:

void function()
{  
    try  
    {    
        std::list<int>::iterator fd_it;
        fd_it++;  
    } catch(...) {}
}

发生的异常不会被标准C ++ try / catch块捕获,也不会被_set_se_translator()设置的任何SEH转换器函数_set_se_translator() 相反,DLL崩溃,并且使用DLL的程序被中止。 我们使用Visual C ++ 2005编译,使用选项/ SHa。 有谁知道在C ++ / Win32中是否可以捕获这些问题并制作一个rockolid DLL包装器?

制作坚如磐石的DLL包装器的唯一方法是将错误的DLL加载到另一个进程中,这样如果它崩溃了,它就不会让你的主进程失效。

捕获所有C ++异常似乎是合理的,但捕获所有结构化异常是另一回事。 SEH 似乎可以让你在那里大部分时间,因为它允许你捕获访问冲突,被零除异常等。

但是,如果有错误的DLL碰巧从另一个线程的堆栈触及一个未提交的页面怎么办? 内存访问将页面错误,异常处理程序将被调用,现在该页面不再是一个保护页面。 当该线程需要增加堆栈时,它将获得访问冲突,并且该进程将崩溃。 这些 帖子更详细地描述了这个案例。)

另一个可能的问题:错误的DLL在持有同步对象时崩溃,但您使用SEH来捕获异常。 如果您的进程尝试获取相同的同步对象,则它会死锁而不是崩溃。 共享同步对象可能是C运行时或操作系统的一部分:如果有错误的DLL 1加载有错误的DLL 2,它在DllMain()崩溃,而有缺陷的DLL 1持有加载程序锁,该怎么办? 下次加载DLL时你的进程是否会死锁?

有关为何(以及具有类似问题的IsBadReadPtr()等函数)滥用SEH的原因的更多信息:

在Windows上,C ++有两种不同的异常样式:C ++和SEH异常。

SEH是一种仅限Windows的异常形式( 有点类似于UNIX中的信号)。 这更像是系统级异常。 它们将被抛出进行无效指针访问,对齐问题等操作......

如果你想捕获Windows上的C ++应用程序可以抛出的每个异常,你需要同时捕获它们。 幸运的是,有一种方法可以混合使用C ++和SEH异常。 我最近写了一篇关于此的详细博客文章,它应该会帮助你。

http://blogs.msdn.com/jaredpar/archive/2008/01/11/mixing-seh-and-c-exceptions.aspx

在标准库容器上增加迭代器永远不会抛出C ++异常。 它可能会给你未定义的行为。

下面的代码取自Zeus 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__except中 ,如下所示:

  __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);
  }

Konrad Rudolph:当然这段代码包含一个“逻辑错误”,它用来说明可能出现的问题。 就像男人说他希望能够保护他的dll免受任何可能的错误。 你认为这不是一个合理的问题吗? 听说过供应商的产品。 我们中的一些人生活在现实世界中,生活在真正的问题中。 只是不可能解决其他人的问题

代码包含逻辑错误(如果有的话)。 由于逻辑错误构成错误,请不要吞下异常 - 修复错误

当然,这是特定于特定代码的。 其他人提供了更多一般性建议。 然而,我发现,很多其实更喜欢固定逻辑错误捕获异常,这是不可接受的。

你看过windows API函数SetUnhandledExceptionFilter吗?

我通常在DllMain函数中调用它,并在DLL崩溃时生成一个小型转储。 但是:(a)我不知道它是否捕获应用程序异常以及DLL异常,以及(b)我不知道您是否可以让程序执行可以继续返回处理程序。 文档说是,但我从来没有这样做过。

在发现异常后你会做什么(特别是对于SEH例外)?

实际上,您不能对流程的状态做出任何假设,实际上您唯一的选择是(可选)转储核心并退出。

从长远来看,任何企图和程序都绝对会给你带来麻烦。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM