Reported by: Lennart Borgman <lennart.borgman <at> gmail.com>
Date: Mon, 11 Oct 2010 15:26:02 UTC
Severity: normal
Tags: wontfix
Merged with 7170
Done: Glenn Morris <rgm <at> gnu.org>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: grischka <grishka <at> gmx.de> To: lennart.borgman <at> gmail.com Cc: bug-gnu-emacs <at> gnu.org Subject: bug#7190: Crash in menus on w32 Date: Thu, 21 Oct 2010 13:11:25 +0200
[Message part 1 (text/plain, inline)]
Here's a patch that fixes the bug. Actually 4 bugs: 1) the initial cause: was freeing items prematurely and trying to free already freed items 2) memory leak: was trying to free items from already deleted menu 3) memory leak: was trying to free menu from already deleted window 4) other: was trying to set cursor in window with no associated frame --- grischka
[free-menu-strings.diff (text/plain, inline)]
commit 064225db78640a1fb48b68aac603c8e05cc69b80 Author: grischka <grischka> Date: Thu Oct 14 13:23:38 2010 +0200 fix w32menu ownerdraw string alloc/free diff --git a/src/w32fns.c b/src/w32fns.c index 8085035..83d577e 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -76,7 +76,6 @@ extern void free_frame_menubar (struct frame *); extern double atof (const char *); extern int w32_console_toggle_lock_key (int, Lisp_Object); extern void w32_menu_display_help (HWND, HMENU, UINT, UINT); -extern void w32_free_menu_strings (HWND); extern const char *map_w32_filename (const char *, const char **); extern int quit_char; @@ -280,12 +279,7 @@ unsigned int msh_mousewheel = 0; /* Timers */ #define MOUSE_BUTTON_ID 1 #define MOUSE_MOVE_ID 2 -#define MENU_FREE_ID 3 #define HOURGLASS_ID 4 -/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP - is received. */ -#define MENU_FREE_DELAY 1000 -static unsigned menu_free_timer = 0; /* In dispnew.c */ @@ -3387,21 +3381,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) KillTimer (hwnd, mouse_move_timer); mouse_move_timer = 0; } - else if (wParam == menu_free_timer) - { - KillTimer (hwnd, menu_free_timer); - menu_free_timer = 0; - f = x_window_to_frame (dpyinfo, hwnd); - /* If a popup menu is active, don't wipe its strings. */ - if (menubar_in_use - && current_popup_menu == NULL) - { - /* Free memory used by owner-drawn and help-echo strings. */ - w32_free_menu_strings (hwnd); - f->output_data.w32->menubar_active = 0; - menubar_in_use = 0; - } - } else if (wParam == hourglass_timer) { KillTimer (hwnd, hourglass_timer); @@ -3465,14 +3444,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_EXITMENULOOP: f = x_window_to_frame (dpyinfo, hwnd); - /* If a menu is still active, check again after a short delay, - since Windows often (always?) sends the WM_EXITMENULOOP - before the corresponding WM_COMMAND message. - Don't do this if a popup menu is active, since it is only - menubar menus that require cleaning up in this way. - */ if (f && menubar_in_use && current_popup_menu == NULL) - menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL); + { + f->output_data.w32->menubar_active = 0; + menubar_in_use = 0; + } /* If hourglass cursor should be displayed, display it now. */ if (f && f->output_data.w32->hourglass_p) @@ -3632,15 +3608,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) goto command; case WM_COMMAND: menubar_in_use = 0; - f = x_window_to_frame (dpyinfo, hwnd); - if (f && HIWORD (wParam) == 0) - { - if (menu_free_timer) - { - KillTimer (hwnd, menu_free_timer); - menu_free_timer = 0; - } - } case WM_MOVE: case WM_SIZE: command: @@ -3748,6 +3715,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (LOWORD (lParam) == HTCLIENT) { f = x_window_to_frame (dpyinfo, hwnd); + if (!f) + return 0; if (f->output_data.w32->hourglass_p && !menubar_in_use && !current_popup_menu) SetCursor (f->output_data.w32->hourglass_cursor); diff --git a/src/w32menu.c b/src/w32menu.c index ff6bd97..78d59fc 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -108,7 +108,7 @@ static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object); static void utf8to16 (unsigned char *, int, WCHAR *); static int fill_in_menu (HMENU, widget_value *); -void w32_free_menu_strings (HWND); +static void w32_free_menu_strings (HMENU); /* This is set nonzero after the user activates the menu bar, and set @@ -347,8 +347,6 @@ menubar_selection_callback (FRAME_PTR f, void * client_data) buf.kind = MENU_BAR_EVENT; buf.frame_or_window = frame; buf.arg = entry; - /* Free memory used by owner-drawn and help-echo strings. */ - w32_free_menu_strings (FRAME_W32_WINDOW (f)); kbd_buffer_store_event (&buf); f->output_data.w32->menubar_active = 0; @@ -357,8 +355,6 @@ menubar_selection_callback (FRAME_PTR f, void * client_data) i += MENU_ITEMS_ITEM_LENGTH; } } - /* Free memory used by owner-drawn and help-echo strings. */ - w32_free_menu_strings (FRAME_W32_WINDOW (f)); f->output_data.w32->menubar_active = 0; } @@ -588,6 +584,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) if (menubar_widget) { + w32_free_menu_strings (menubar_widget); /* Empty current menubar, rather than creating a fresh one. */ while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION)) ; @@ -643,6 +640,7 @@ free_frame_menubar (FRAME_PTR f) HMENU old = GetMenu (FRAME_W32_WINDOW (f)); SetMenu (FRAME_W32_WINDOW (f), NULL); f->output_data.w32->menubar_widget = NULL; + w32_free_menu_strings (old); DestroyMenu (old); } @@ -898,10 +896,11 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, /* Free the widget_value objects we used to specify the contents. */ free_menubar_widget_value_tree (first_wv); + /* Free the owner-drawn and help-echo menu strings. */ + w32_free_menu_strings (menu); DestroyMenu (menu); + current_popup_menu = NULL; - /* Free the owner-drawn and help-echo menu strings. */ - w32_free_menu_strings (FRAME_W32_WINDOW (f)); f->output_data.w32->menubar_active = 0; /* Find the selected item, and its pane, to return @@ -1651,9 +1650,11 @@ w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags) /* Free memory used by owner-drawn strings. */ static void -w32_free_submenu_strings (HMENU menu) +w32_free_menu_strings (HMENU menu) { int i, num = GetMenuItemCount (menu); + if (!get_menu_item_info) + return; for (i = 0; i < num; i++) { MENUITEMINFO info; @@ -1674,29 +1675,10 @@ w32_free_submenu_strings (HMENU menu) /* Recurse down submenus. */ if (info.hSubMenu) - w32_free_submenu_strings (info.hSubMenu); + w32_free_menu_strings (info.hSubMenu); } } -void -w32_free_menu_strings (HWND hwnd) -{ - HMENU menu = current_popup_menu; - - if (get_menu_item_info) - { - /* If there is no popup menu active, free the strings from the frame's - menubar. */ - if (!menu) - menu = GetMenu (hwnd); - - if (menu) - w32_free_submenu_strings (menu); - } - - current_popup_menu = NULL; -} - #endif /* HAVE_MENUS */ /* The following is used by delayed window autoselection. */ diff --git a/src/w32term.c b/src/w32term.c index 1f53860..0cef1b7 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5734,11 +5734,11 @@ x_free_frame_resources (struct frame *f) if (FRAME_FACE_CACHE (f)) free_frame_faces (f); + free_frame_menubar (f); + if (FRAME_W32_WINDOW (f)) my_destroy_window (f, FRAME_W32_WINDOW (f)); - free_frame_menubar (f); - unload_color (f, FRAME_FOREGROUND_PIXEL (f)); unload_color (f, FRAME_BACKGROUND_PIXEL (f)); unload_color (f, f->output_data.w32->cursor_pixel);
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.