Paul Gofman : ntdll: Support nested exceptions on x64.

Alexandre Julliard julliard at winehq.org
Fri Aug 14 16:39:31 CDT 2020


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

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Fri Aug 14 12:08:25 2020 +0300

ntdll: Support nested exceptions on x64.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/signal_x86_64.c   |  6 ++---
 dlls/ntdll/tests/exception.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 28e4ec8ca6..0cbcc177b2 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -380,10 +380,10 @@ NTSTATUS WINAPI RtlWow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *co
 static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
                                                CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
 {
-    if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) return ExceptionContinueSearch;
+    if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
+        rec->ExceptionFlags |= EH_NESTED_CALL;
 
-    /* FIXME */
-    return ExceptionNestedException;
+    return ExceptionContinueSearch;
 }
 
 /**********************************************************************
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index f74ddde0f2..b6307264bc 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -68,6 +68,10 @@ typedef struct _RTL_UNLOAD_EVENT_TRACE
 static RTL_UNLOAD_EVENT_TRACE *(WINAPI *pRtlGetUnloadEventTrace)(void);
 static void (WINAPI *pRtlGetUnloadEventTraceEx)(ULONG **element_size, ULONG **element_count, void **event_trace);
 
+#ifndef EH_NESTED_CALL
+#define EH_NESTED_CALL 0x10
+#endif
+
 #if defined(__x86_64__)
 typedef struct
 {
@@ -3782,6 +3786,65 @@ static void test_kiuserexceptiondispatcher(void)
     ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
 }
 
+static BOOL got_nested_exception, got_prev_frame_exception;
+static void *nested_exception_initial_frame;
+
+static DWORD nested_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+        CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
+{
+    trace("nested_exception_handler Rip %p, Rsp %p, code %#x, flags %#x, ExceptionAddress %p.\n",
+            (void *)context->Rip, (void *)context->Rsp, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress);
+
+    if (rec->ExceptionCode == 0x80000003
+            && !(rec->ExceptionFlags & EH_NESTED_CALL))
+    {
+        ok(rec->NumberParameters == 1, "Got unexpected rec->NumberParameters %u.\n", rec->NumberParameters);
+        ok((void *)context->Rsp == frame, "Got unexpected frame %p.\n", frame);
+        ok(*(void **)frame == (char *)code_mem + 5, "Got unexpected *frame %p.\n", *(void **)frame);
+        ok(context->Rip == (ULONG_PTR)((char *)code_mem + 7), "Got unexpected Rip %#lx.\n", context->Rip);
+
+        nested_exception_initial_frame = frame;
+        RaiseException(0xdeadbeef, 0, 0, 0);
+        ++context->Rip;
+        return ExceptionContinueExecution;
+    }
+
+    if (rec->ExceptionCode == 0xdeadbeef && rec->ExceptionFlags == EH_NESTED_CALL)
+    {
+        ok(!rec->NumberParameters, "Got unexpected rec->NumberParameters %u.\n", rec->NumberParameters);
+        got_nested_exception = TRUE;
+        ok(frame == nested_exception_initial_frame, "Got unexpected frame %p.\n", frame);
+        return ExceptionContinueSearch;
+    }
+
+    ok(rec->ExceptionCode == 0xdeadbeef && !rec->ExceptionFlags,
+            "Got unexpected exception code %#x, flags %#x.\n", rec->ExceptionCode, rec->ExceptionFlags);
+    ok(!rec->NumberParameters, "Got unexpected rec->NumberParameters %u.\n", rec->NumberParameters);
+    ok(frame == (void *)((BYTE *)nested_exception_initial_frame + 8),
+            "Got unexpected frame %p.\n", frame);
+    got_prev_frame_exception = TRUE;
+    return ExceptionContinueExecution;
+}
+
+static void test_nested_exception(void)
+{
+    static const BYTE except_code[] =
+    {
+        0xe8, 0x02, 0x00, 0x00, 0x00, /* call nest */
+        0x90,                         /* nop */
+        0xc3,                         /* ret */
+        /* nest: */
+        0xcc,                         /* int3 */
+        0x90,                         /* nop */
+        0xc3,                         /* ret  */
+    };
+
+    got_nested_exception = got_prev_frame_exception = FALSE;
+    run_exception_test(nested_exception_handler, NULL, except_code, ARRAY_SIZE(except_code), PAGE_EXECUTE_READ);
+    ok(got_nested_exception, "Did not get nested exception.\n");
+    ok(got_prev_frame_exception, "Did not get nested exception in the previous frame.\n");
+}
+
 #elif defined(__arm__)
 
 static void test_thread_context(void)
@@ -5450,6 +5513,7 @@ START_TEST(exception)
     test_dpe_exceptions();
     test_wow64_context();
     test_kiuserexceptiondispatcher();
+    test_nested_exception();
 
     if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
       test_dynamic_unwind();




More information about the wine-cvs mailing list