[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