user32: Fail if inserting a submenu would create a loop in the menu hierarchy.

Rein Klazes wijn at online.nl
Fri Jul 24 02:18:34 CDT 2009


Fixes the stack fault in bug #12171
---
 dlls/user32/menu.c       |   37 +++++++++++++++++++++++++++++++++++--
 dlls/user32/tests/menu.c |    4 ++--
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c
index 8b43ff2..5311b43 100644
--- a/dlls/user32/menu.c
+++ b/dlls/user32/menu.c
@@ -147,6 +147,11 @@ typedef struct
 #define MENU_TOP_MARGIN 3
 #define MENU_BOTTOM_MARGIN 2
 
+/* maximum allowed depth of any branch in the menu tree.
+ * This value is slightly larger than in windows (25) to
+ * stay on the safe side. */
+#define MAXMENUDEPTH 30
+
   /* (other menu->FocusedItem values give the position of the focused item) */
 #define NO_SELECTED_ITEM  0xffff
 
@@ -4641,6 +4646,30 @@ static inline void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicod
 
 
 /**********************************************************************
+ *		MENU_depth
+ *
+ * detect if there are loops in the menu tree (or the depth is too large)
+ */
+static int MENU_depth( POPUPMENU *pmenu, int depth)
+{
+    int i;
+    MENUITEM *item;
+
+    depth++;
+    if( depth > MAXMENUDEPTH) return depth;
+    item = pmenu->items;
+    for( i = 0; i < pmenu->nItems && depth <= MAXMENUDEPTH; i++, item++){
+        POPUPMENU *psubmenu =  MENU_GetMenu( item->hSubMenu);
+        if( psubmenu){
+            int bdepth = MENU_depth( psubmenu, depth);
+            if( bdepth > depth) depth = bdepth;
+        }
+    }
+    return depth;
+}
+
+
+/**********************************************************************
  *		SetMenuItemInfo_common
  *
  * Note: does not support the MIIM_TYPE flag. Use the MIIM_FTYPE,
@@ -4678,10 +4707,14 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
 	if (menu->hSubMenu) {
 	    POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
 	    if (subMenu) {
+                if( MENU_depth( subMenu, 0) > MAXMENUDEPTH) {
+                    ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
+                    menu->hSubMenu = 0;
+                    return FALSE;
+                }
 		subMenu->wFlags |= MF_POPUP;
 		menu->fType |= MF_POPUP;
-	    }
-	    else {
+	    } else {
                 SetLastError( ERROR_INVALID_PARAMETER);
                 return FALSE;
             }
diff --git a/dlls/user32/tests/menu.c b/dlls/user32/tests/menu.c
index 7382ec0..a1af944 100644
--- a/dlls/user32/tests/menu.c
+++ b/dlls/user32/tests/menu.c
@@ -3018,6 +3018,7 @@ static void test_menu_maxdepth(void)
     int i;
     DWORD ret;
 
+    SetLastError(12345678);
     for( i = 0; i < NR_MENUS; i++) {
         hmenus[i] = CreatePopupMenu();
         if( !hmenus[i]) break;
@@ -3028,7 +3029,7 @@ static void test_menu_maxdepth(void)
         if( !ret) break;
     }
     trace("Maximum depth is %d\n", i);
-todo_wine
+    ok( GetLastError() == 12345678, "unexpected error %d\n",  GetLastError());
     ok( i < NR_MENUS ||
            broken( i == NR_MENUS), /* win98, NT */
            "no ( or very large) limit on menu depth!\n");
@@ -3055,7 +3056,6 @@ static void test_menu_circref(void)
     ok( ret, "AppendMenu failed, error is %d\n", GetLastError());
     /* now attempt to change the string of the first item of menu1 */
     ret = ModifyMenuA( menu1, (UINT_PTR)menu2, MF_POPUP, (UINT_PTR)menu2, "menu 2");
-todo_wine
     ok( !ret ||
             broken( ret), /* win98, NT */
             "ModifyMenu should have failed.\n");
-- 
1.6.3.3




More information about the wine-patches mailing list