user32: Add exception handling for timer callbacks (with tests)

Peter Dons Tychsen (none) donpedro at donpedro.
Sun Sep 20 21:29:39 CDT 2009


This fixes bug #20094
Tested on Windows-XP.
---
 dlls/user32/message.c   |   36 +++++++++++++++++++++++++++++++-----
 dlls/user32/tests/msg.c |   17 +++++++++++++++++
 2 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index 3f7a4cd..5018a49 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -43,6 +43,7 @@
 #include "win.h"
 #include "controls.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msg);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
@@ -3065,8 +3066,20 @@ LRESULT WINAPI DispatchMessageA( const MSG* msg )
       /* Process timer messages */
     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
     {
-        if (msg->lParam) return CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd,
-                                                 msg->message, msg->wParam, GetTickCount() );
+        if (msg->lParam)
+	{
+	    __TRY
+	    {
+	        retval = CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd,
+		    msg->message, msg->wParam, GetTickCount() );
+            }
+	    __EXCEPT_PAGE_FAULT
+            {
+	        retval = 0;
+            }
+            __ENDTRY
+	    return retval;
+	}
     }
     if (!msg->hwnd) return 0;
 
@@ -3103,7 +3116,8 @@ LRESULT WINAPI DispatchMessageA( const MSG* msg )
  * If the lpMsg parameter points to a WM_TIMER message and the
  * parameter of the WM_TIMER message is not NULL, the lParam parameter
  * points to the function that is called instead of the window
- * procedure.
+ * procedure. The function stored in lParam (timer callback) is protected
+ * from causing page-faults.
  *
  * The message must be valid.
  *
@@ -3123,8 +3137,20 @@ LRESULT WINAPI DispatchMessageW( const MSG* msg )
       /* Process timer messages */
     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
     {
-        if (msg->lParam) return CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd,
-                                                 msg->message, msg->wParam, GetTickCount() );
+        if (msg->lParam)
+	{
+	    __TRY
+	    {
+	        retval = CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd,
+		    msg->message, msg->wParam, GetTickCount() );
+            }
+	    __EXCEPT_PAGE_FAULT
+            {
+	        retval = 0;
+            }
+            __ENDTRY
+	    return retval;
+	}
     }
     if (!msg->hwnd) return 0;
 
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 540b494..0d2115f 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -7813,6 +7813,16 @@ static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
 {
 }
 
+static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
+{
+    /* Crash on purpose */
+    int *test = (int*)0;
+    if(*test)
+    {
+        ok(1,"Avoid getting optimized away");
+    }
+}
+
 #define TIMER_ID  0x19
 
 static DWORD WINAPI timer_thread_proc(LPVOID x)
@@ -7834,6 +7844,7 @@ static void test_timers(void)
 {
     struct timer_info info;
     DWORD id;
+    MSG msg;
 
     info.hWnd = CreateWindow ("TestWindowClass", NULL,
        WS_OVERLAPPEDWINDOW ,
@@ -7855,6 +7866,12 @@ static void test_timers(void)
 
     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
 
+    /* Test timer callback with crash */
+    info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash);
+    ok(info.id, "SetTimer failed\n");
+    Sleep(150);
+    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
+
     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
 }
 
-- 
1.6.2.5


--=-SJjai468z0lNg1y83GHK--




More information about the wine-patches mailing list