简体   繁体   English

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

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

Like the title says, we're looking for a way to catch all exceptions from a piece of C++ code, and wrap this in a dll. 就像标题所说,我们正在寻找一种方法来捕获一段C ++代码中的所有异常,并将其包装在一个DLL中。 This way we can shield of the application that uses this dll, from any errors occurring in this dll. 这样我们可以屏蔽使用此dll的应用程序,从此dll中发生的任何错误。

However, this does not seem possible with C++ under Windows. 但是,在Windows下使用C ++似乎不太可行。

Example: 例:

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

The exception that occurs is not caught by the standard C++ try/catch block, nor by any SEH translator function set by _set_se_translator() . 发生的异常不会被标准C ++ try / catch块捕获,也不会被_set_se_translator()设置的任何SEH转换器函数_set_se_translator() Instead, the DLL crashes, and the program that uses the DLL is aborted. 相反,DLL崩溃,并且使用DLL的程序被中止。 We compiled with Visual C++ 2005, with the option /SHa. 我们使用Visual C ++ 2005编译,使用选项/ SHa。 Does anyone know if it's possible in C++/Win32 to catch these kind of problems and make a rocksolid DLL wrapper? 有谁知道在C ++ / Win32中是否可以捕获这些问题并制作一个rockolid DLL包装器?

The only way to make a rock solid DLL wrapper is to load the buggy DLL in another process, so that if it crashes it doesn't take your primary process down with it. 制作坚如磐石的DLL包装器的唯一方法是将错误的DLL加载到另一个进程中,这样如果它崩溃了,它就不会让你的主进程失效。

Catching all C++ exceptions seems reasonable, but catching all structured exceptions is another story. 捕获所有C ++异常似乎是合理的,但捕获所有结构化异常是另一回事。 SEH might seem to get you most of the way there, because it allows you to catch access violations, divide-by-zero exceptions, etc. SEH 似乎可以让你在那里大部分时间,因为它允许你捕获访问冲突,被零除异常等。

But what if the buggy DLL happens to touch an uncommitted page from another thread's stack? 但是,如果有错误的DLL碰巧从另一个线程的堆栈触及一个未提交的页面怎么办? The memory access will page fault, the exception handler will be invoked, and now that page is no longer a guard page. 内存访问将页面错误,异常处理程序将被调用,现在该页面不再是一个保护页面。 When that thread needs to grow the stack, it will get an access violation, and the process will crash. 当该线程需要增加堆栈时,它将获得访问冲突,并且该进程将崩溃。 ( These posts describe this case in more detail.) 这些 帖子更详细地描述了这个案例。)

Another likely problem: the buggy DLL crashes while holding a synchronization object, but you use SEH to catch the exception. 另一个可能的问题:错误的DLL在持有同步对象时崩溃,但您使用SEH来捕获异常。 If your process attempts to acquire the same synchronization object, then it deadlocks instead of crashing. 如果您的进程尝试获取相同的同步对象,则它会死锁而不是崩溃。 The shared synchronization object may be part of the C runtime or the OS: what if buggy DLL 1 loads buggy DLL 2, which crashes in its DllMain() while buggy DLL 1 is holding the loader lock? 共享同步对象可能是C运行时或操作系统的一部分:如果有错误的DLL 1加载有错误的DLL 2,它在DllMain()崩溃,而有缺陷的DLL 1持有加载程序锁,该怎么办? Will your process deadlock the next time it loads a DLL? 下次加载DLL时你的进程是否会死锁?

For more information on why this (and functions like IsBadReadPtr() , which have similar problems) is a misuse of SEH: 有关为何(以及具有类似问题的IsBadReadPtr()等函数)滥用SEH的原因的更多信息:

On Windows, C++ has 2 different styles of exceptions: C++ and SEH exceptions. 在Windows上,C ++有两种不同的异常样式:C ++和SEH异常。

SEH is a windows only form of exceptions ( somewhat akin to signals in UNIX). SEH是一种仅限Windows的异常形式( 有点类似于UNIX中的信号)。 It's more of a system level exception. 这更像是系统级异常。 They will be thrown for such operations as invalid pointer accesses, alignment issues, etc ... 它们将被抛出进行无效指针访问,对齐问题等操作......

If you want to catch every exception that can be thrown by a C++ app on windows you will need to catch both. 如果你想捕获Windows上的C ++应用程序可以抛出的每个异常,你需要同时捕获它们。 Fortunately there is a way to mix the use of C++ and SEH exceptions. 幸运的是,有一种方法可以混合使用C ++和SEH异常。 I wrote a detailed blog post about this recently, it should help you out. 我最近写了一篇关于此的详细博客文章,它应该会帮助你。

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

Incrementing an iterator on a standard libary container will never throw a C++ exception. 在标准库容器上增加迭代器永远不会抛出C ++异常。 It may give you undefined behaviour. 它可能会给你未定义的行为。

The code below is taken from the Zeus IDE. 下面的代码取自Zeus IDE。 It will trap any Windows generated exceptions: 它将捕获任何Windows生成的异常:

Step #1: Define an Exception Filter Function 步骤#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;
  }

Step #2: Wrap the code in a __try and __except as shown below: 步骤#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: Of course this code contains a "logic error", it's to illustrate a problem that could occur. Konrad Rudolph:当然这段代码包含一个“逻辑错误”,它用来说明可能出现的问题。 Like the man says he wants to be able to shield his dll from any possible errors. 就像男人说他希望能够保护他的dll免受任何可能的错误。 You don't think this is a legitimate question? 你认为这不是一个合理的问题吗? Heard of vendor products. 听说过供应商的产品。 Some of us live in the real world and live with real problems. 我们中的一些人生活在现实世界中,生活在真正的问题中。 It's just not possible to fix everyone else's problems 只是不可能解决其他人的问题

This code contains a logic error, if at all. 代码包含逻辑错误(如果有的话)。 Since a logic error constitues a bug, don't swallow the exception – fix the error ! 由于逻辑错误构成错误,请不要吞下异常 - 修复错误

Of course, this is specific to the particular code. 当然,这是特定于特定代码的。 Others have offered more general advice. 其他人提供了更多一般性建议。 However, I've found that a lot of people actually do prefer catching exceptions over fixing logic errors and this is simply unacceptable. 然而,我发现,很多其实更喜欢固定逻辑错误捕获异常,这是不可接受的。

Have you looked at the windows API function SetUnhandledExceptionFilter? 你看过windows API函数SetUnhandledExceptionFilter吗?

I usually call it in the DllMain function and have it generate a minidump when the DLL crashes. 我通常在DllMain函数中调用它,并在DLL崩溃时生成一个小型转储。 However: (a) I don't know if it traps application exceptions as well as DLL exceptions, and (b) I don't know if you can have the handler return in such a way that program execution can continue. 但是:(a)我不知道它是否捕获应用程序异常以及DLL异常,以及(b)我不知道您是否可以让程序执行可以继续返回处理程序。 The docs say yes, but I've never done it. 文档说是,但我从来没有这样做过。

What are you going to do after you catch the exception (especially for SEH exceptions)? 在发现异常后你会做什么(特别是对于SEH例外)?

In reality you can make no assumptions about the state of the process, realistically the only option you have is to (optionally) dump core and exit. 实际上,您不能对流程的状态做出任何假设,实际上您唯一的选择是(可选)转储核心并退出。

Any attempt and proceeding is absolutely going to cause you problems in the long run. 从长远来看,任何企图和程序都绝对会给你带来麻烦。

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

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