Module: wine Branch: master Commit: 38dbe067c370610d0a2423d1ce7702e36ddd2679 URL: http://source.winehq.org/git/wine.git/?a=commit;h=38dbe067c370610d0a2423d1ce...
Author: Rein Klazes wijn@online.nl Date: Fri Jul 24 09:18:34 2009 +0200
user32: Fail if inserting a submenu would create a loop in the menu hierarchy.
---
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 460378c..203340a 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
@@ -4627,6 +4632,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, @@ -4664,10 +4693,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");