MSVCRT: added support for re-throwing exceptions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



LICENSE: LGPL

If you compile the following code with Visual C++ using the /MD option (so 
that it uses msvcrt.dll)

class CExceptionClass
{
public:
   CExceptionClass() {number=0;}
   long number;
};

void doSomething()
{
   try {
     throw CExceptionClass();
   } catch(...) {
     throw;
   }
}

int main(int argc, char* argv[])
{
   try {
     doSomething();
   } catch(CExceptionClass& e) {
     printf("%d\n",e.number);
   }
   return 0;
}

and run it under WINE, it will crash. This because the "throw;" statement 
used to re-throw the last thrown exception ends up calling 
CxxThrowException with a NULL object and type, and the code that dispatches 
it to the right catch handler is not prepared to handle this situation.
The fix adds support for holding the last exception in the thread local 
storage, and re-throwing when requested, plus some error checking to 
avoiding access violations when handling exceptions.

Alberto

===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/cppexcept.c,v
retrieving revision 1.2
diff -u -r1.2 cppexcept.c
--- cppexcept.c 12 Sep 2002 22:07:03 -0000      1.2
+++ cppexcept.c 28 Oct 2002 09:39:14 -0000
@@ -171,6 +171,8 @@
  static void dump_exception_type( cxx_exception_type *type )
  {
      int i;
+    if(type==NULL)
+        return;

      DPRINTF( "exception type:\n" );
      DPRINTF( "flags %x destr %p handler %p type info %p\n",
@@ -235,6 +237,8 @@
  static cxx_type_info *find_caught_type( cxx_exception_type *exc_type, 
catchblock_info *catchblock )
  {
      UINT i;
+    if(exc_type==NULL || exc_type->type_info_table==NULL)
+        return NULL;

      for (i = 0; i < exc_type->type_info_table->count; i++)
      {
@@ -291,7 +295,6 @@
  {
      void (*handler)();
      int trylevel = frame->trylevel;
-
      while (trylevel != last_level)
      {
          if (trylevel < 0 || trylevel >= descr->unwind_count)
@@ -300,13 +303,13 @@
              MSVCRT_terminate();
          }
          handler = descr->unwind_table[trylevel].handler;
+        trylevel = descr->unwind_table[trylevel].prev;
          if (handler)
          {
              TRACE( "calling unwind handler %p trylevel %d last %d ebp %p\n",
                     handler, trylevel, last_level, &frame->ebp );
              call_ebp_func( handler, &frame->ebp );
          }
-        trylevel = descr->unwind_table[trylevel].prev;
      }
      frame->trylevel = last_level;
  }
@@ -383,9 +386,10 @@
      if (!descr->tryblock_count) return ExceptionContinueSearch;

      exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
+
      if (rec->ExceptionCode != CXX_EXCEPTION) goto normal_handler;
      if (rec->ExceptionInformation[0] != CXX_FRAME_MAGIC) goto normal_handler;
-    if (exc_type->custom_handler)
+    if (exc_type!=NULL && exc_type->custom_handler)
          return exc_type->custom_handler( rec, frame, exc_context, 
dispatch, descr, 0, 0, 0 );

   normal_handler:
@@ -425,10 +429,23 @@
  /*********************************************************************
   *             _CxxThrowException (MSVCRT.@)
   */
+
+extern DWORD LastExceptionObj_tls_index, LastExceptionType_tls_index;
+
  void _CxxThrowException( void *object, cxx_exception_type *type )
  {
      DWORD args[3];

+    if(object==NULL && type==NULL)
+    {
+        object=TlsGetValue(LastExceptionObj_tls_index);
+        type=(cxx_exception_type*)TlsGetValue(LastExceptionType_tls_index);
+    }
+    else
+    {
+        TlsSetValue(LastExceptionObj_tls_index,object);
+        TlsSetValue(LastExceptionType_tls_index,type);
+    }
      args[0] = CXX_FRAME_MAGIC;
      args[1] = (DWORD)object;
      args[2] = (DWORD)type;
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/main.c,v
retrieving revision 1.12
diff -u -r1.12 main.c
--- main.c      25 Oct 2002 03:12:01 -0000      1.12
+++ main.c      28 Oct 2002 09:39:18 -0000
@@ -29,6 +29,10 @@
  /* Index to TLS */
  DWORD MSVCRT_tls_index;

+/* TLS for re-throwing exceptions */
+DWORD LastExceptionObj_tls_index;
+DWORD LastExceptionType_tls_index;
+
  static inline BOOL msvcrt_init_tls(void);
  static inline BOOL msvcrt_free_tls(void);
  const char* msvcrt_get_reason(DWORD reason) WINE_UNUSED;
@@ -91,12 +95,36 @@
      ERR("TlsAlloc() failed!\n");
      return FALSE;
    }
+
+  LastExceptionObj_tls_index=TlsAlloc();
+  if (LastExceptionObj_tls_index == TLS_OUT_OF_INDEXES)
+  {
+    ERR("TlsAlloc() failed!\n");
+    return FALSE;
+  }
+
+  LastExceptionType_tls_index=TlsAlloc();
+  if(LastExceptionType_tls_index == TLS_OUT_OF_INDEXES)
+  {
+    ERR("TlsAlloc() failed!\n");
+    return FALSE;
+  }
    return TRUE;
  }

  static inline BOOL msvcrt_free_tls(void)
  {
    if (!TlsFree(MSVCRT_tls_index))
+  {
+    ERR("TlsFree() failed!\n");
+    return FALSE;
+  }
+  if (!TlsFree(LastExceptionObj_tls_index))
+  {
+    ERR("TlsFree() failed!\n");
+    return FALSE;
+  }
+  if (!TlsFree(LastExceptionType_tls_index))
    {
      ERR("TlsFree() failed!\n");
      return FALSE;




[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux