Piotr Caban : msvcrt: Improve x86_64 nested exceptions handling.

Alexandre Julliard julliard at winehq.org
Wed Jul 6 09:57:30 CDT 2016


Module: wine
Branch: master
Commit: d9bacd98d8d23aefdd22755dc1ac4e3c67002921
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=d9bacd98d8d23aefdd22755dc1ac4e3c67002921

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Jul  5 14:28:45 2016 +0200

msvcrt: Improve x86_64 nested exceptions handling.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcrt/except_x86_64.c | 48 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c
index 0379d30..d6d4b04 100644
--- a/dlls/msvcrt/except_x86_64.c
+++ b/dlls/msvcrt/except_x86_64.c
@@ -339,6 +339,7 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
     ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0);
     int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase),
             descr->ipmap_count, dispatch->ControlPc-dispatch->ImageBase);
+    const tryblock_info *in_catch;
     EXCEPTION_RECORD catch_record;
     CONTEXT context;
     UINT i, j;
@@ -374,24 +375,38 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
         }
     }
 
+    for (i=descr->tryblock_count; i>0; i--)
+    {
+        in_catch = rva_to_ptr(descr->tryblock, dispatch->ImageBase);
+        in_catch = &in_catch[i-1];
+
+        if (trylevel>in_catch->end_level && trylevel<=in_catch->catch_level)
+            break;
+    }
+    if (!i)
+        in_catch = NULL;
+
     unwind_help = rva_to_ptr(descr->unwind_help, orig_frame);
-    unwind_help[0] = trylevel;
-    TRACE("current trylevel: %d, last catch block: %d\n", trylevel, unwind_help[1]);
+    if (trylevel > unwind_help[1])
+        unwind_help[0] = unwind_help[1] = trylevel;
+    else
+        trylevel = unwind_help[1];
+    TRACE("current trylevel: %d\n", trylevel);
 
     for (i=0; i<descr->tryblock_count; i++)
     {
         const tryblock_info *tryblock = rva_to_ptr(descr->tryblock, dispatch->ImageBase);
         tryblock = &tryblock[i];
 
-        if (unwind_help[1] != -1)
-        {
-            if (unwind_help[1] < tryblock->start_level) continue;
-            if (unwind_help[1] > tryblock->end_level) continue;
-        }
-
         if (trylevel < tryblock->start_level) continue;
         if (trylevel > tryblock->end_level) continue;
 
+        if (in_catch)
+        {
+            if(tryblock->start_level <= in_catch->end_level) continue;
+            if(tryblock->end_level > in_catch->catch_level) continue;
+        }
+
         /* got a try block */
         for (j=0; j<tryblock->catchblock_count; j++)
         {
@@ -419,8 +434,6 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
                 TRACE("found catch(...) block\n");
             }
 
-            unwind_help[1] = tryblock->end_level+1;
-
             /* unwind stack and call catch */
             memset(&catch_record, 0, sizeof(catch_record));
             catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
@@ -433,7 +446,7 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
             catch_record.ExceptionInformation[4] = (ULONG_PTR)rec;
             catch_record.ExceptionInformation[5] =
                 (ULONG_PTR)rva_to_ptr(catchblock->handler, dispatch->ImageBase);
-            RtlUnwindEx((void*)orig_frame, 0, &catch_record, NULL, &context, NULL);
+            RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &context, NULL);
         }
     }
 
@@ -460,15 +473,22 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
             ULONG64 orig_frame = rec->ExceptionInformation[1];
             const cxx_function_descr *descr = (void*)rec->ExceptionInformation[2];
             int end_level = rec->ExceptionInformation[3];
+            EXCEPTION_RECORD *new_rec = (void*)rec->ExceptionInformation[4];
+            thread_data_t *data = msvcrt_get_thread_data();
             frame_info *cur;
 
             cxx_local_unwind(orig_frame, dispatch, descr, end_level);
 
             /* FIXME: we should only unregister frames registered by call_catch_block here */
-            for (cur = msvcrt_get_thread_data()->frame_info_head; cur; cur = cur->next)
+            for (cur = data->frame_info_head; cur; cur = cur->next)
             {
-                if ((ULONG64)cur > frame)
-                    __CxxUnregisterExceptionObject((cxx_frame_info*)cur, FALSE);
+                if ((ULONG64)cur <= frame)
+                {
+                    __CxxUnregisterExceptionObject((cxx_frame_info*)cur,
+                            new_rec->ExceptionCode == CXX_EXCEPTION &&
+                            data->exc_record->ExceptionCode == CXX_EXCEPTION &&
+                            new_rec->ExceptionInformation[1] == data->exc_record->ExceptionInformation[1]);
+                }
             }
             return ExceptionContinueSearch;
         }




More information about the wine-cvs mailing list