Jacek Caban : user32: Limit number of hooks called recursively.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Jun 29 08:12:09 CDT 2015


Module: wine
Branch: master
Commit: 4bcb4881ae9e7fc2cc4d32aa3ba7f36e46d6fc5c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=4bcb4881ae9e7fc2cc4d32aa3ba7f36e46d6fc5c

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Fri Jun 26 19:37:41 2015 +0200

user32: Limit number of hooks called recursively.

---

 dlls/user32/hook.c         | 15 ++++++++++++-
 dlls/user32/tests/msg.c    | 54 +++++++++++++++++++++++++++++++++++++++++++++-
 dlls/user32/user_private.h |  1 +
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c
index 281b88e..090ec17 100644
--- a/dlls/user32/hook.c
+++ b/dlls/user32/hook.c
@@ -413,7 +413,19 @@ static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARA
     }
     else if (info->proc)
     {
+        struct user_thread_info *thread_info = get_user_thread_info();
         HMODULE free_module = 0;
+
+        /*
+         * Windows protects from stack overflow in recursive hook calls. Different Windows
+         * allow different depths.
+         */
+        if (thread_info->hook_call_depth >= 25)
+        {
+            WARN("Too many hooks called recursively, skipping call.\n");
+            return 0;
+        }
+
         TRACE( "calling hook %p %s code %x wp %lx lp %lx module %s\n",
                info->proc, hook_names[info->id-WH_MINHOOK], code, wparam,
                lparam, debugstr_w(info->module) );
@@ -421,16 +433,17 @@ static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARA
         if (!info->module[0] ||
             (info->proc = get_hook_proc( info->proc, info->module, &free_module )) != NULL)
         {
-            struct user_thread_info *thread_info = get_user_thread_info();
             HHOOK prev = thread_info->hook;
             BOOL prev_unicode = thread_info->hook_unicode;
 
             thread_info->hook = info->handle;
             thread_info->hook_unicode = info->next_unicode;
+            thread_info->hook_call_depth++;
             ret = call_hook_proc( info->proc, info->id, code, wparam, lparam,
                                   info->prev_unicode, info->next_unicode );
             thread_info->hook = prev;
             thread_info->hook_unicode = prev_unicode;
+            thread_info->hook_call_depth--;
 
             if (free_module) FreeLibrary(free_module);
         }
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index a515550..831a56b 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9182,6 +9182,54 @@ todo_wine {
 	"unexpected error %d\n", GetLastError());
 }
 
+static HWND hook_hwnd;
+static HHOOK recursive_hook;
+static int hook_depth, max_hook_depth;
+
+static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
+{
+    LRESULT res;
+    MSG msg;
+    BOOL b;
+
+    hook_depth++;
+    if(hook_depth > max_hook_depth)
+        max_hook_depth = hook_depth;
+
+    b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
+    ok(b, "PeekMessage failed\n");
+
+    res = CallNextHookEx(recursive_hook, code, w, l);
+
+    hook_depth--;
+    return res;
+}
+
+static void test_recursive_hook(void)
+{
+    MSG msg;
+    BOOL b;
+
+    hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
+    ok(hook_hwnd != NULL, "CreateWindow failed\n");
+
+    recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
+    ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
+
+    PostMessageW(hook_hwnd, WM_USER, 0, 0);
+    PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
+
+    hook_depth = 0;
+    GetMessageW(&msg, hook_hwnd, 0, 0);
+    ok(15 < max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
+    trace("max_hook_depth = %d\n", max_hook_depth);
+
+    b = UnhookWindowsHookEx(recursive_hook);
+    ok(b, "UnhokWindowsHookEx failed\n");
+
+    DestroyWindow(hook_hwnd);
+}
+
 static const struct message ScrollWindowPaint1[] = {
     { WM_PAINT, sent },
     { WM_ERASEBKGND, sent|beginpaint },
@@ -14946,7 +14994,11 @@ START_TEST(msg)
     test_timers();
     test_timers_no_wnd();
     test_timers_exceptions();
-    if (hCBT_hook) test_set_hook();
+    if (hCBT_hook)
+    {
+        test_set_hook();
+        test_recursive_hook();
+    }
     test_DestroyWindow();
     test_DispatchMessage();
     test_SendMessageTimeout();
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 1fbecb9..d3affb0 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -175,6 +175,7 @@ struct user_thread_info
     DWORD                         changed_mask;           /* Current queue changed mask */
     WORD                          recursion_count;        /* SendMessage recursion counter */
     WORD                          message_count;          /* Get/PeekMessage loop counter */
+    WORD                          hook_call_depth;        /* Number of recursively called hook procs */
     BOOL                          hook_unicode;           /* Is current hook unicode? */
     HHOOK                         hook;                   /* Current hook */
     struct received_message_info *receive_info;           /* Message being currently received */




More information about the wine-cvs mailing list