From 5e65a77ff8c907d5560164c30a24d1bf171b3b8f Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Tue, 12 Apr 2016 19:03:57 +0200
Subject: ntdll: Improve handling of builtin frames for x86_64 when switching
 stacks.

---
 dlls/ntdll/signal_x86_64.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index b56c1ea..93475d54 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2420,16 +2420,20 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
             if (status != STATUS_UNHANDLED_EXCEPTION) return status;
         }
         /* hack: call wine handlers registered in the tib list */
-        else while ((ULONG64)teb_frame < new_context.Rsp)
+        else if ((ULONG64)teb_frame >= context.Rsp)
         {
-            TRACE( "found wine frame %p rsp %lx handler %p\n",
-                   teb_frame, new_context.Rsp, teb_frame->Handler );
-            dispatch.EstablisherFrame = (ULONG64)teb_frame;
-            context = *orig_context;
-            status = call_teb_handler( rec, &dispatch, teb_frame, orig_context );
-            if (status != STATUS_UNHANDLED_EXCEPTION) return status;
-            teb_frame = teb_frame->Prev;
+            while ((ULONG64)teb_frame < new_context.Rsp)
+            {
+                TRACE( "found wine frame %p rsp %lx handler %p\n",
+                       teb_frame, new_context.Rsp, teb_frame->Handler );
+                dispatch.EstablisherFrame = (ULONG64)teb_frame;
+                context = *orig_context;
+                status = call_teb_handler( rec, &dispatch, teb_frame, orig_context );
+                if (status != STATUS_UNHANDLED_EXCEPTION) return status;
+                teb_frame = teb_frame->Prev;
+            }
         }
+        else WARN( "skipping wine frame %p (on other stack?)\n", teb_frame );
 
         if (new_context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
         context = new_context;
@@ -3592,7 +3596,8 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
             if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EH_TARGET_UNWIND;
             call_unwind_handler( rec, &dispatch );
         }
-        else  /* hack: call builtin handlers registered in the tib list */
+        /* hack: call builtin handlers registered in the tib list */
+        else if ((ULONG64)teb_frame >= context->Rsp)
         {
             DWORD64 backup_frame = dispatch.EstablisherFrame;
             while ((ULONG64)teb_frame < new_context.Rsp && (ULONG64)teb_frame < (ULONG64)end_frame)
@@ -3605,6 +3610,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
             if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Rsp) break;
             dispatch.EstablisherFrame = backup_frame;
         }
+        else WARN( "skipping wine frame %p (on other stack?)\n", teb_frame );
 
         if (dispatch.EstablisherFrame == (ULONG64)end_frame) break;
         *context = new_context;
-- 
2.7.1

