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