简体   繁体   中英

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. This way we can shield of the application that uses this dll, from any errors occurring in this dll.

However, this does not seem possible with C++ under Windows.

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() . Instead, the DLL crashes, and the program that uses the DLL is aborted. We compiled with Visual C++ 2005, with the option /SHa. Does anyone know if it's possible in C++/Win32 to catch these kind of problems and make a rocksolid DLL wrapper?

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.

Catching all C++ exceptions seems reasonable, but catching all structured exceptions is another story. SEH might seem to get you most of the way there, because it allows you to catch access violations, divide-by-zero exceptions, etc.

But what if the buggy DLL happens to touch an uncommitted page from another thread's stack? 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. 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? Will your process deadlock the next time it loads a DLL?

For more information on why this (and functions like IsBadReadPtr() , which have similar problems) is a misuse of SEH:

On Windows, C++ has 2 different styles of exceptions: C++ and SEH exceptions.

SEH is a windows only form of exceptions ( somewhat akin to signals in 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. Fortunately there is a way to mix the use of C++ and SEH exceptions. 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

Incrementing an iterator on a standard libary container will never throw a C++ exception. It may give you undefined behaviour.

The code below is taken from the Zeus IDE. It will trap any Windows generated exceptions:

Step #1: Define an Exception Filter Function

  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:

  __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. Like the man says he wants to be able to shield his dll from any possible errors. 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?

I usually call it in the DllMain function and have it generate a minidump when the DLL crashes. 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. 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)?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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