[PATCH v2 3/6] user32/tests: Add tests for UOI_TIMERPROC_EXCEPTION_SUPPRESSION.

Jinoh Kang jinoh.kang.kr at gmail.com
Wed Apr 20 11:03:43 CDT 2022


Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

Notes:
    v1 -> v2:
    - shorten line width
    - s/SetUserObjectInformation/SetUserObjectInformationW/
    - add case for UOI config performed prior to the dispatch
    - mark UOI_TIMERPROC_EXCEPTION_SUPPRESSION exception handling as broken
    - deal with EXCEPTION_BREAKPOINT IP rewinding on x86/x64 architectures.
    - explicitly test for exception handling phase
    - skip exception tests if on non-PE build or compiler has no SEH support

 dlls/user32/tests/msg.c | 189 ++++++++++++++++++++++++++++++++++++++++
 include/wine/asm.h      |   1 +
 2 files changed, 190 insertions(+)

diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 918ee97bfa5..7fb8469ec2a 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -34,6 +34,8 @@
 #include "commctrl.h"
 
 #include "wine/test.h"
+#include "wine/asm.h"
+#include "wine/exception.h"
 
 #define MDI_FIRST_CHILD_ID 2004
 
@@ -10647,11 +10649,33 @@ static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR
     count++;
 }
 
+enum timer_exception_phase {
+    TIMER_EXCEPTION_INITIAL,
+    TIMER_EXCEPTION_RAISED,
+    TIMER_EXCEPTION_CONTINUE,
+    TIMER_EXCEPTION_CONTINUE_OK,
+};
+
 static DWORD exception;
+static enum timer_exception_phase timer_exc_phase;
+static BOOL *tproc_exc_suppress = NULL;
 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 {
+    if (tproc_exc_suppress)
+    {
+        BOOL res = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION,
+                                             tproc_exc_suppress, sizeof(*tproc_exc_suppress));
+        todo_wine
+        ok(res, "SetUserObjectInformationW error %lu\n", GetLastError());
+        tproc_exc_suppress = NULL;
+    }
+
     count++;
+    timer_exc_phase = TIMER_EXCEPTION_RAISED;
     RaiseException(exception, 0, 0, NULL);
+    ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE,
+       "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE, timer_exc_phase);
+    timer_exc_phase = TIMER_EXCEPTION_CONTINUE_OK;
 }
 
 static DWORD WINAPI timer_thread_proc(LPVOID x)
@@ -10813,10 +10837,127 @@ static void test_timers_no_wnd(void)
     while (i > 0) KillTimer(NULL, ids[--i]);
 }
 
+static LONG WINAPI timer_exception_filter(EXCEPTION_POINTERS *eptr)
+{
+    if (timer_exc_phase == TIMER_EXCEPTION_RAISED &&
+        eptr->ExceptionRecord->ExceptionCode == exception &&
+        eptr->ExceptionRecord->ExceptionFlags == 0 &&
+        eptr->ExceptionRecord->NumberParameters == 0)
+    {
+        if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
+        {
+#if defined(__i386__)
+            if ((ULONG_PTR)eptr->ExceptionRecord->ExceptionAddress == eptr->ContextRecord->Eip + 1)
+                eptr->ContextRecord->Eip++;  /* cancel EIP rewinding */
+#elif defined(__x86_64__)
+            if ((ULONG_PTR)eptr->ExceptionRecord->ExceptionAddress == eptr->ContextRecord->Rip + 1)
+                eptr->ContextRecord->Rip++;  /* cancel RIP rewinding */
+#endif
+        }
+        timer_exc_phase = TIMER_EXCEPTION_CONTINUE;
+        return EXCEPTION_CONTINUE_EXECUTION;
+    }
+
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+
+extern void dispatch_message_handle_exception(const MSG *msg);
+
+#if defined(USE_COMPILER_EXCEPTIONS) || defined(__i386__)
+void dispatch_message_handle_exception(const MSG *msg)
+{
+    __TRY
+    {
+        DispatchMessageA( msg );
+    }
+    __EXCEPT(timer_exception_filter)
+    {
+    }
+    __ENDTRY
+}
+#else
+EXCEPTION_DISPOSITION WINAPI timer_exception_handler( EXCEPTION_RECORD *rec,
+                                                      void *frame,
+                                                      CONTEXT *context,
+                                                      DISPATCHER_CONTEXT *dispatch )
+{
+    EXCEPTION_POINTERS ptrs = { rec, context };
+
+    if (timer_exception_filter( &ptrs ) == EXCEPTION_CONTINUE_EXECUTION)
+        return ExceptionContinueExecution;
+
+    return ExceptionContinueSearch;
+}
+#if defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED)
+__ASM_GLOBAL_FUNC( dispatch_message_handle_exception,
+                   __ASM_SEH(".seh_handler " __ASM_NAME("timer_exception_handler") ", @except\n\t")
+                   "subq $0x28,%rsp\n\t"
+                   __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
+                   __ASM_SEH(".seh_stackalloc 0x28\n\t")
+                   __ASM_SEH(".seh_endprologue\n\t")
+                   "callq *__imp_DispatchMessageA(%rip)\n\t"
+                   "nop\n\t"
+                   "addq $0x28,%rsp\n\t"
+                   __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
+                   "ret" );
+#elif defined(__arm__) && defined(__WINE_PE_BUILD)
+__ASM_GLOBAL_FUNC( dispatch_message_handle_exception,
+                   "1:\n\t"
+                   "push {r4,lr}\n\t"
+                   __ASM_CFI(".cfi_def_cfa_offset 8\n\t")
+                   __ASM_CFI(".cfi_offset r4, -8\n\t")
+                   __ASM_CFI(".cfi_offset lr, -4\n\t")
+                   "ldr ip, =__imp_DispatchMessageA\n\t"
+                   "ldr ip, [ip]\n\t"
+                   "blx ip\n\t"
+                   "pop {r4,pc}\n"
+                   "2:\n\t"
+                   ".section \".pdata\", \"dr\"\n\t"
+                   ".rva " __ASM_NAME("dispatch_message_handle_exception") "\n\t"
+                   ".rva .Lunwind__dispatch_message_handle_exception\n\t"
+                   ".section \".xdata\", \"dr\"\n"
+                   ".Lunwind__dispatch_message_handle_exception:\n\t"
+                   ".long 0x10100000 + ((2b - 1b) / 2)\n\t"
+                   ".long 0xfbfbffd4\n\t"
+                   ".rva " __ASM_NAME("timer_exception_handler") "\n\t"
+                   ".text" );
+#elif defined(__aarch64__) && defined(__ASM_SEH_SUPPORTED)
+__ASM_GLOBAL_FUNC( dispatch_message_handle_exception,
+                   __ASM_SEH(".seh_handler " __ASM_NAME("timer_exception_handler") ", @except\n\t")
+                   "stp x29, x30, [sp, #-16]!\n\t"
+                   __ASM_CFI(".cfi_def_cfa_offset 16\n\t")
+                   __ASM_CFI(".cfi_offset x29, -16\n\t")
+                   __ASM_CFI(".cfi_offset x30, -8\n\t")
+                   __ASM_SEH(".seh_save_fplr_x 16\n\t")
+                   __ASM_SEH(".seh_endprologue\n\t")
+                   "mov x29, sp\n\t"
+                   "adrp x8, __imp_DispatchMessageA\n\t"
+                   "ldr x8, [x8, :lo12:__imp_DispatchMessageA]\n\t"
+                   "blr x8\n\t"
+                   "nop\n\t"
+                   __ASM_SEH(".seh_startepilogue\n\t")
+                   "ldp x29, x30, [sp], #16\n\t"
+                   __ASM_CFI(".cfi_restore x29\n\t")
+                   __ASM_CFI(".cfi_restore x30\n\t")
+                   __ASM_CFI(".cfi_def_cfa sp, 0\n\t")
+                   __ASM_SEH(".seh_save_fplr_x 16\n\t")
+                   __ASM_SEH(".seh_endepilogue\n\t")
+                   "ret" );
+#else
+void dispatch_message_handle_exception(const MSG *msg)
+{
+    skip("dispatch_message_handle_exception not implemented on this build configuration\n");
+    count++;
+    timer_exc_phase = TIMER_EXCEPTION_CONTINUE_OK;
+}
+#endif
+#endif
+
 static void test_timers_exception(DWORD code)
 {
     UINT_PTR id;
     MSG msg;
+    BOOL ret, value;
 
     exception = code;
     id = SetTimer(NULL, 0, 1000, callback_exception);
@@ -10828,8 +10969,56 @@ static void test_timers_exception(DWORD code)
     msg.lParam = (LPARAM)callback_exception;
 
     count = 0;
+    timer_exc_phase = TIMER_EXCEPTION_INITIAL;
     DispatchMessageA(&msg);
     ok(count == 1, "did not get one count as expected (%i).\n", count);
+    ok(timer_exc_phase == TIMER_EXCEPTION_RAISED,
+       "expected phase %d, got %d\n", TIMER_EXCEPTION_RAISED, timer_exc_phase);
+
+    value = FALSE;
+    ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION,
+                                    &value, sizeof(value));
+    if (!ret && GetLastError() == ERROR_INVALID_FUNCTION)
+    {
+        win_skip("UOI_TIMERPROC_EXCEPTION_SUPPRESSION not supported on this platform\n");
+    }
+    else
+    {
+        todo_wine
+        ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError());
+
+        count = 0;
+        timer_exc_phase = TIMER_EXCEPTION_INITIAL;
+        dispatch_message_handle_exception(&msg);
+        ok(count == 1, "expected count to be 1, got %d\n", count);
+        todo_wine
+        ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK ||
+           broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */,
+           "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase);
+
+        value = TRUE;
+        ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION,
+                                        &value, sizeof(value));
+        todo_wine
+        ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError());
+
+        value = FALSE;
+        tproc_exc_suppress = &value;
+        count = 0;
+        timer_exc_phase = TIMER_EXCEPTION_INITIAL;
+        dispatch_message_handle_exception(&msg);
+        ok(count == 1, "expected count to be 1, got %d\n", count);
+        todo_wine
+        ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK ||
+           broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */,
+           "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase);
+
+        value = TRUE;
+        ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION,
+                                        &value, sizeof(value));
+        todo_wine
+        ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError());
+    }
 
     KillTimer(NULL, id);
 }
diff --git a/include/wine/asm.h b/include/wine/asm.h
index 0547ee94b19..9200491afd0 100644
--- a/include/wine/asm.h
+++ b/include/wine/asm.h
@@ -50,6 +50,7 @@
 #  define __ASM_SEH(str)
 # else
 #  define __ASM_SEH(str) str
+#  define __ASM_SEH_SUPPORTED
 # endif
 #else
 # define __ASM_SEH(str)
-- 
2.34.1




More information about the wine-devel mailing list