unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* NT Emacs crashes when selecting a menubar item
@ 2002-07-24 18:55 David Ponce
  2002-07-25 18:07 ` Richard Stallman
  0 siblings, 1 reply; 13+ messages in thread
From: David Ponce @ 2002-07-24 18:55 UTC (permalink / raw)


Hi All,

Sometimes when I select an item on the menu bar Emacs crashes because
it try to access a bad memory location.  Sometimes also this even
crashes Windows NT because of a page fault!

I managed to get a backtrace (see at end) using Dr. Mingw, a
Just-In-Time debugger.  It shows that the problem occurs in the
function `free_menubar_widget_value_tree' which try to free a
corrupted `widget_value' data structure.  Would it be possible that
the GC corrupted it?  Unfortunately, I don't know enough the Emacs
internals to give more useful informations :-(

What I can say is that the problem seems to occur when I use complex
imenu indexes (generated by Semantic).  Also sometimes I noticed that
I got garbaged imenu item names.

Hope this will help.
David

In GNU Emacs 21.3.50.1 (i386-mingw-nt4.0.1381)
 of 2002-07-24 on EBAT311
configured using `configure --with-gcc (2.95)'

Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: ENU
  locale-coding-system: iso-latin-1
  default-enable-multibyte-characters: t

------------- Dr. Mingw backtrace
emacs.exe caused an Access Violation at location 01110446 in module
emacs.exe Reading from location 63746189.

Registers:
eax=6374616d ebx=6374616d ecx=0082ffe0 edx=0fe8007a esi=00000020 
edi=11555c04
eip=01110446 esp=0082f3e8 ebp=0082f400 iopl=0         nv up ei pl nz na 
pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             
efl=00000202

Call stack:
01110446  emacs.exe:01110446  free_menubar_widget_value_tree  w32menu.c:1081
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = ,
        char * value = ,
        char * key = ,
        int help = ,
        Boolean enabled = ,
        Boolean selected = ,
        enum button_type button_type = ,
        Boolean title = ,
        struct _widget_value * contents = ,
        XtPointer call_data = ,
        struct _widget_value * next =
    }
)
    ...
      wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
   
 >      if (wv->contents && (wv->contents != (widget_value*)1))
        {
          free_menubar_widget_value_tree (wv->contents);
    ...

0111046B  emacs.exe:0111046B  free_menubar_widget_value_tree  w32menu.c:1084
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 875524,
        Boolean enabled = 'H',
        Boolean selected = 'i',
        enum button_type button_type = 1751607660,
        Boolean title = 't',
        struct _widget_value * contents = 0x6374616d,
        XtPointer call_data = 0x20646568,
        struct _widget_value * next = 0x746e7953
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->contents);
 >          wv->contents = (widget_value *) 0xDEADBEEF;
        }
      if (wv->next)
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x0000049d,
        struct _widget_value * next = 0x008381f8
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x0083b660
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x00000468,
        struct _widget_value * next = 0x00838020
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x00000453,
        struct _widget_value * next = 0x0083c4a0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x0000043e,
        struct _widget_value * next = 0x00839030
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x000003f1,
        struct _widget_value * next = 0x0083c1b0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

0111046B  emacs.exe:0111046B  free_menubar_widget_value_tree  w32menu.c:1084
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828210548,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00837fc0,
        XtPointer call_data = 0x000003e5,
        struct _widget_value * next = 0x00000000
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->contents);
 >          wv->contents = (widget_value *) 0xDEADBEEF;
        }
      if (wv->next)
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828210452,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x000003dd,
        struct _widget_value * next = 0x00838eb0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x0083dfa0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828210308,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x00000378,
        struct _widget_value * next = 0x0083c0f0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x0000030b,
        struct _widget_value * next = 0x00838350
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x00000269,
        struct _widget_value * next = 0x0083bde0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x0083c680
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828116292,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x00000259,
        struct _widget_value * next = 0x00838260
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828116084,
        Boolean enabled = 0,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x00000251,
        struct _widget_value * next = 0x0083bdb0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828102516,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x000001e4,
        struct _widget_value * next = 0x0083c050
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 824014472,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x000001dc,
        struct _widget_value * next = 0x0083b7e0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 824014552,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x000001d4,
        struct _widget_value * next = 0x00838f10
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 824014640,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x000001cc,
        struct _widget_value * next = 0x0083c1e0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 828101908,
        Boolean enabled = 0,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x00000000,
        XtPointer call_data = 0x000001c4,
        struct _widget_value * next = 0x0083c180
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

0111046B  emacs.exe:0111046B  free_menubar_widget_value_tree  w32menu.c:1084
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x0083c120,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x0083b8d0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->contents);
 >          wv->contents = (widget_value *) 0xDEADBEEF;
        }
      if (wv->next)
    ...

01110485  emacs.exe:01110485  free_menubar_widget_value_tree  w32menu.c:1089
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0xdeadbeef,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x00837ed0
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->next);
 >          wv->next = (widget_value *) 0xDEADBEEF;
        }
      BLOCK_INPUT;
    ...

0111046B  emacs.exe:0111046B  free_menubar_widget_value_tree  w32menu.c:1084
void free_menubar_widget_value_tree(
    widget_value * wv = &{
        char * name = 0xdeadbeef,
        char * value = 0xdeadbeef,
        char * key = 0xdeadbeef,
        int help = 290806788,
        Boolean enabled = 1,
        Boolean selected = 0,
        enum button_type button_type = BUTTON_TYPE_NONE,
        Boolean title = 0,
        struct _widget_value * contents = 0x0083c470,
        XtPointer call_data = 0x00000000,
        struct _widget_value * next = 0x00000000
    }
)
    ...
        {
          free_menubar_widget_value_tree (wv->contents);
 >          wv->contents = (widget_value *) 0xDEADBEEF;
        }
      if (wv->next)
    ...

01110E7B  emacs.exe:01110E7B  set_frame_menubar  w32menu.c:1517
void set_frame_menubar(
    FRAME_PTR f = &{
        int size = 536871998,
        struct Lisp_Vector * next = 0x01ce8300,
        int name = 843753044,
        int icon_name = 290806788,
        int title = 290806788,
        int focus_frame = 290806788,
        int root_window = 1108712448,
        int selected_window = 1108712448,
        int minibuffer_window = 1104072192,
        int param_alist = 1373797428,
        int scroll_bars = 1113417728,
        int condemned_scroll_bars = 290806788,
        int menu_bar_items = 1104009216,
        int face_alist = 1372527148,
        int menu_bar_vector = 1104330752,
        int menu_bar_items_used = 5893,
        int buffer_predicate = 290806788,
        int buffer_list = 1375180340,
        int menu_bar_window = 1104156672,
        int tool_bar_window = 1104163328,
        int tool_bar_items = 290806788,
        int desired_tool_bar_string = 290806788,
        int current_tool_bar_string = 290806788,
        struct face_cache * face_cache = 0x01cea520,
        char * namebuf = 0x01575f68,
        struct glyph_pool * current_pool = 0x00000000,
        struct glyph_pool * desired_pool = 0x00000000,
        struct glyph_matrix * desired_matrix = 0x00000000,
        struct glyph_matrix * current_matrix = 0x00000000,
        unsigned int glyphs_initialized_p,
        int tool_bar_lines = 0,
        int n_tool_bar_items = 0,
        char * decode_mode_spec_buffer = 0x01d05e00,
        int * insert_line_cost = 0x02088900,
        int * delete_line_cost = 0x01e06300,
        int * insert_n_lines_cost = 0x01e06200,
        int * delete_n_lines_cost = 0x01ff0000,
        int height = 35,
        int width = 96,
        int window_width = 100,
        int window_height = 0,
        int new_height = 0,
        int new_width = 0,
        enum output_method output_method = output_w32,
        union output_data output_data = {
            struct x_output * x = 0x01cddb00,
            struct w32_output * w32 = 0x01cddb00,
            struct mac_output * mac = 0x01cddb00,
            int nothing = 30268160
        },
        int menu_bar_lines = 0,
        int external_menu_bar = 1,
        char display_preempted = 0,
        char visible = 1,
        char iconified = 0,
        char async_visible = 1,
        char async_iconified = 0,
        char garbaged = 0,
        char has_minibuffer = 1,
        char wants_modeline = 1,
        char can_have_scroll_bars = 1,
        enum vertical_scroll_bar_type vertical_scroll_bar_type
                  = vertical_scroll_bar_right,
        char auto_raise = 0,
        char auto_lower = 0,
        char no_split = 0,
        char explicit_name = 0,
        char window_sizes_changed = 0,
        char * message_buf = 0x01d05000,
        int scroll_bottom_vpos = -1,
        int scroll_bar_pixel_width = 16,
        int scroll_bar_cols = 2,
        int cost_calculation_baud_rate = 19200,
        char mouse_moved = 1,
        double gamma = 0.000000,
        int extra_line_spacing = 0,
        unsigned int resized_p
    },
    int first_time = 0,
    int deep_p = 1
)
    ...
   
      {
 >        HMENU old_widget = f->output_data.w32->menubar_widget;
   
        f->output_data.w32->menubar_widget = menubar_widget;
    ...

011101DF  emacs.exe:011101DF  x_activate_menubar  w32menu.c:958
void x_activate_menubar(
    FRAME_PTR f = &{
        int size = 536871998,
        struct Lisp_Vector * next = 0x01ce8300,
        int name = 843753044,
        int icon_name = 290806788,
        int title = 290806788,
        int focus_frame = 290806788,
        int root_window = 1108712448,
        int selected_window = 1108712448,
        int minibuffer_window = 1104072192,
        int param_alist = 1373797428,
        int scroll_bars = 1113417728,
        int condemned_scroll_bars = 290806788,
        int menu_bar_items = 1104009216,
        int face_alist = 1372527148,
        int menu_bar_vector = 1104330752,
        int menu_bar_items_used = 5893,
        int buffer_predicate = 290806788,
        int buffer_list = 1375180340,
        int menu_bar_window = 1104156672,
        int tool_bar_window = 1104163328,
        int tool_bar_items = 290806788,
        int desired_tool_bar_string = 290806788,
        int current_tool_bar_string = 290806788,
        struct face_cache * face_cache = 0x01cea520,
        char * namebuf = 0x01575f68,
        struct glyph_pool * current_pool = 0x00000000,
        struct glyph_pool * desired_pool = 0x00000000,
        struct glyph_matrix * desired_matrix = 0x00000000,
        struct glyph_matrix * current_matrix = 0x00000000,
        unsigned int glyphs_initialized_p,
        int tool_bar_lines = 0,
        int n_tool_bar_items = 0,
        char * decode_mode_spec_buffer = 0x01d05e00,
        int * insert_line_cost = 0x02088900,
        int * delete_line_cost = 0x01e06300,
        int * insert_n_lines_cost = 0x01e06200,
        int * delete_n_lines_cost = 0x01ff0000,
        int height = 35,
        int width = 96,
        int window_width = 100,
        int window_height = 0,
        int new_height = 0,
        int new_width = 0,
        enum output_method output_method = output_w32,
        union output_data output_data = {
            struct x_output * x = 0x01cddb00,
            struct w32_output * w32 = 0x01cddb00,
            struct mac_output * mac = 0x01cddb00,
            int nothing = 30268160
        },
        int menu_bar_lines = 0,
        int external_menu_bar = 1,
        char display_preempted = 0,
        char visible = 1,
        char iconified = 0,
        char async_visible = 1,
        char async_iconified = 0,
        char garbaged = 0,
        char has_minibuffer = 1,
        char wants_modeline = 1,
        char can_have_scroll_bars = 1,
        enum vertical_scroll_bar_type vertical_scroll_bar_type
                  = vertical_scroll_bar_right,
        char auto_raise = 0,
        char auto_lower = 0,
        char no_split = 0,
        char explicit_name = 0,
        char window_sizes_changed = 0,
        char * message_buf = 0x01d05000,
        int scroll_bottom_vpos = -1,
        int scroll_bar_pixel_width = 16,
        int scroll_bar_cols = 2,
        int cost_calculation_baud_rate = 19200,
        char mouse_moved = 1,
        double gamma = 0.000000,
        int extra_line_spacing = 0,
        unsigned int resized_p
    }
)
    ...
   
      /* Signal input thread to return from WM_INITMENU.  */
 >      complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
    }
   
    ...

01009761  emacs.exe:01009761  kbd_buffer_get_event  keyboard.c:3783
static int kbd_buffer_get_event(
    KBOARD * * kbp = &0x0125d220,
    int * used_mouse_menu = &0
)
    ...
      input_pending = readable_events (0);
      if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
 >        x_activate_menubar (XFRAME (event->frame_or_window));
    }
    #endif
    ...

010081C3  emacs.exe:010081C3  read_char  keyboard.c:2638
int read_char(
    int commandflag = 1,
    int nmaps = 11,
    int * maps = &1373421628,
    int prev_event = 290806788,
    int * used_mouse_menu = &0
)
    ...
          restore_getcjmp (local_getcjmp);
          timer_start_idle ();
 >          c = kbd_buffer_get_event (&kb, used_mouse_menu);
          restore_getcjmp (save_jump);
   
    ...

0100EAC9  emacs.exe:0100EAC9  read_key_sequence  keyboard.c:8363
static int read_key_sequence(
    int * keybuf = &299433876,
    int bufsize = 30,
    int prompt = 290806788,
    int dont_downcase_last = 0,
    int can_return_switch_frame = 1,
    int fix_current_buffer = 1
)
    ...
          }
    #endif
 >        key = read_char (NILP (prompt), nmaps,
         (Lisp_Object *) submaps, last_nonmenu_event,
         &used_mouse_menu);
    ...

01006750  emacs.exe:01006750  command_loop_1  keyboard.c:1470
int command_loop_1(
   
)
    ...
   
          /* Read next key sequence; i gets its length.  */
 >          i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
         Qnil, 0, 1, 1);
   
    ...

0101AE4C  emacs.exe:0101AE4C  internal_condition_case  eval.c:1349
int internal_condition_case(
    int ()(void) * bfun = &0x01006454,
    int handlers = 290929124,
    int ()(void) * hfun = &0x01005f64
)
    ...
      handlerlist = &h;
   
 >      val = (*bfun) ();
      catchlist = c.next;
      handlerlist = h.next;
    ...

01006210  emacs.exe:01006210  command_loop_2  keyboard.c:1271
int command_loop_2(
   
)
    ...
   
      do
 >        val = internal_condition_case (command_loop_1, Qerror, cmd_error);
      while (!NILP (val));
   
    ...

0101A9E4  emacs.exe:0101A9E4  internal_catch  eval.c:1109
int internal_catch(
    int tag = 290881452,
    int ()(void) * func = &0x010061f0,
    int arg = 290806788
)
    ...
      /* Call FUNC.  */
      if (! _setjmp (c.jmp))
 >        c.val = (*func) (arg);
   
      /* Throw works by a longjmp that comes right here.  */
    ...

010061C2  emacs.exe:010061C2  command_loop  keyboard.c:1251
int command_loop(
   
)
    ...
    internal_catch (Qtop_level, top_level_1, Qnil);
    internal_catch (Qtop_level, command_loop_2, Qnil);
 >    executing_macro = Qnil;
   
    /* End of file in -batch run causes exit here.  */
    ...

01005D33  emacs.exe:01005D33  recursive_edit_1  keyboard.c:966
int recursive_edit_1(
   
)
    ...
      redisplaying_p = 0;
   
 >      val = command_loop ();
      if (EQ (val, Qt))
        Fsignal (Qquit, Qnil);
    ...

01005E5F  emacs.exe:01005E5F  Frecursive_edit  keyboard.c:1023
int Frecursive_edit(
   
)
    ...
   
      recursive_edit_1 ();
 >      return unbind_to (count, Qnil);
    }
   
    ...

01003298  emacs.exe:01003298  main  emacs.c:1627
int main(
    int argc = 1,
    char * * argv = &0x012584c0,
    char * * envp = &0x43414d45
)
    ...
      Frecursive_edit ();
      /* NOTREACHED */
 >      return 0;
    }
   
    ...

010010EC  emacs.exe:010010EC
01001203  emacs.exe:01001203
010042CD  emacs.exe:010042CD  _start  unexw32.c:135
void _start(
   
)
    ...
      nCmdShow = SW_SHOWDEFAULT;
    #endif
 >      mainCRTStartup ();
    }
   
    ...

77F1BBB5  KERNEL32.dll:77F1BBB5  GetProcessPriorityBoost

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-24 18:55 David Ponce
@ 2002-07-25 18:07 ` Richard Stallman
  2002-07-26 12:30   ` David Ponce
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Stallman @ 2002-07-25 18:07 UTC (permalink / raw)
  Cc: emacs-devel

The widget_value structures are not Lisp data; they are explicitly
allocated and freed.  So I don't think GC is responsible for this.
It appears to me that ASCII text got written throughout the
last real widget_value structure encountered:

        int help = 875524,
        Boolean enabled = 'H',
        Boolean selected = 'i',
        enum button_type button_type = 1751607660,
        Boolean title = 't',
        struct _widget_value * contents = 0x6374616d,
        XtPointer call_data = 0x20646568,
        struct _widget_value * next = 0x746e7953

This appears to say "Hilight" and "matched Synt".
(I suspect there are three other characters in between them
that did not show up in this output.)

The value of `help' is peculiar since it does not translate
into ASCII text, and yet it does not seem like a valid value
to be there (it would normally be a Lisp string object).

One interesting question is what data is in core before the start of
this object.  Is any ASCII text present there?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-25 18:07 ` Richard Stallman
@ 2002-07-26 12:30   ` David Ponce
  2002-07-27 18:52     ` Richard Stallman
  0 siblings, 1 reply; 13+ messages in thread
From: David Ponce @ 2002-07-26 12:30 UTC (permalink / raw)
  Cc: emacs-devel

>
>
>One interesting question is what data is in core before the start of
>this object.  Is any ASCII text present there?
>
Hi,

I worked a little more on this problem and, simply calling fprintf in
various locations in w32menu.c (I don't have a debugger), I found that
the function `single_submenu' seems to receive corrupted data in
static variable `menu_items'.

Notice that I only observed garbaged menu item names in dynamic menus
like "Buffers" (I use msb) or imenu.

More details...

Only after this line (w32menu.c::1268):

      wv->name = (char *) SDATA (item_name);

The following fprintf showed corrupted data:

fprintf(stderr,
 "single_submenu::1268/wv->name = SDATA (item_name) = %p@%s\n",
 wv->name, wv->name);

Here is a snippet of the printed data (the first value of `item_name'
seems correct, but the next ones are corrupted):

[...]
single_submenu::1268/wv->name = SDATA (item_name) = 01772128@Select and 
Paste
single_submenu::1268/wv->name = SDATA (item_name) = 01EFC1D0@  
wv->name...DEADBEEF;

single_submenu::1268/wv->name = SDATA (item_name) = 01EFC1B4@
  wv->nam...DEADBEEF;

single_submenu::1268/wv->name = SDATA (item_name) = 01EF2B70@: Ditto.
single_submenu::1268/wv->name = SDATA (item_name) = 01EF2B80@: Moved 
definitions.
single_submenu::1268/wv->name = SDATA (item_name) = 01EFC198@K  Void 
va...vironment.
single_submenu::1268/wv->name = SDATA (item_name) = 01EFC17C@;; Unused 
...$nterm))
[...]

`item_name' is a local Lisp_Object variable initialized to
(w32menu.c::1240):

      item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);

`menu_items' is initialized in the function `set_frame_menubar'
(w32menu.c::1395):

      menu_items = f->menu_bar_vector;

It seems that f->menu_bar_vector is setup in keyboard.c in function
`menu_bar_items'.  Maybe is there a problem here?

I had a look at this function, but I lack more knowledge of Emacs
internal (and probably C) to really understand its code.

Nevertheless, I hope this report will help.

David

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-26 12:30   ` David Ponce
@ 2002-07-27 18:52     ` Richard Stallman
  2002-07-28 16:56       ` David Ponce
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Stallman @ 2002-07-27 18:52 UTC (permalink / raw)
  Cc: emacs-devel

    I worked a little more on this problem and, simply calling fprintf in
    various locations in w32menu.c (I don't have a debugger), I found that
    the function `single_submenu' seems to receive corrupted data in
    static variable `menu_items'.

You have made significant progress, but we don't know the answer yet.

Can you determine where that data becomes corrupted?
Is it written wrong at the start, or does it get
clobbered later on?

    `item_name' is a local Lisp_Object variable initialized to
    (w32menu.c::1240):

Can you determine what value item_name has at that point?
Is it a Lisp string?  If so, what is its text?

	  item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);

What is the value of i when the invalid data comes out?
What array index?

    It seems that f->menu_bar_vector is setup in keyboard.c in function
    `menu_bar_items'.  Maybe is there a problem here?

It could be.  Could you examine the contents of this vector
right after that function is finished?  In particular,
what is the value found at the array index that the bad data later
comes from?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-27 18:52     ` Richard Stallman
@ 2002-07-28 16:56       ` David Ponce
  2002-07-29 17:30         ` Richard Stallman
  0 siblings, 1 reply; 13+ messages in thread
From: David Ponce @ 2002-07-28 16:56 UTC (permalink / raw)
  Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2537 bytes --]

Hi Richard,

>You have made significant progress, but we don't know the answer yet.
>
>Can you determine where that data becomes corrupted?
>Is it written wrong at the start, or does it get
>clobbered later on?
>

Thank you for your support!

I worked hard to find the bug that corrupted menu strings, and I
think I finally found it!

In fact, after displaying memory locations of menu item strings in
`widget_value' data structures, I noticed that sometimes their
contents changed (not the location) between their initialization in
`single_submenu' and their use in `add_menu_item'.

This looked like a bad interaction with GC.  I carefully reviewed the
code and was first disappointed because all the Lisp strings that
produced menu item strings seemed correctly protected from GC!  I
looked more thoroughly at the GC code, and discovered that the data
part of Lisp strings may be relocated when GC compacts the Lisp string
storage.  Even when the base string Lisp_Object is protected!

So, I hacked w32menu.c to used safe local copy of menu item strings,
and the bug disappeared :-)

 From that base, I took time to properly update w32menu.c, and fixed
another bug too, related to pop up menu cleanup.  Finally I cleaned
up the code to generalize use of AREF, ASET and ASIZE macros.

Attached you will find the patch, the change log is at end.

With the patch menus work very well now, with no noticeable slow down
(I used the faster Win32 API to alloc/free memory).

I don't know if it is possible, or if that could solve such problems
(is it guaranteed that GC can't raise when a menu is showing up?),
but perhaps a more general solution, probably with more impact, would
be to directly use Lisp strings in `widget_value', like for help
items?

What do you think?

Sincerely,
David

------------------------ Change Log --------------------------------
(local_heap, local_alloc, local_free): New macros.
(malloc_widget_value, free_widget_value)
(free_menubar_widget_value_tree)
(w32_free_submenu_strings): Use them.

(local-string): New function.
(single_submenu, set_frame_menubar)
(w32_menu_show, add_menu_item): Use it.

(push_submenu_start, push_submenu_end, push_left_right_boundary)
(push_menu_pane, push_menu_item, single_keymap_panes)
(single_menu_item, Fx_popup_menu, menubar_selection_callback)
(single_submenu, set_frame_menubar)
(w32_menu_show, w32_dialog_show): Use AREF, ASET, ASIZE.

(Fx_popup_menu):  Don't show pop up menu until preceding one is
actually cleaned up.  Moved UNGCPRO outside #ifdef HAVE_MENUS block.


[-- Attachment #2: w32menu.patch --]
[-- Type: text/x-patch, Size: 31233 bytes --]

*** w32menu.c.ori	Mon Jul 15 10:48:32 2002
--- w32menu.c	Sun Jul 28 18:35:13 2002
***************
*** 112,120 ****
  #endif
  } widget_value;
  
! /* LocalAlloc/Free is a reasonably good allocator.  */
! #define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof (widget_value))
! #define free_widget_value(wv) LocalFree (wv)
  
  /******************************************************************/
  
--- 112,124 ----
  #endif
  } widget_value;
  
! /* Local memory management */
! #define local_heap (GetProcessHeap ())
! #define local_alloc(n) (HeapAlloc (local_heap, HEAP_ZERO_MEMORY, (n)))
! #define local_free(p) (HeapFree (local_heap, 0, ((LPVOID) (p))))
! 
! #define malloc_widget_value() ((widget_value *) local_alloc (sizeof (widget_value)))
! #define free_widget_value(wv) (local_free ((wv)))
  
  /******************************************************************/
  
***************
*** 318,324 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
    menu_items_submenu_depth++;
  }
  
--- 322,328 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qnil);
    menu_items_submenu_depth++;
  }
  
***************
*** 330,336 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
    menu_items_submenu_depth--;
  }
  
--- 334,340 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qlambda);
    menu_items_submenu_depth--;
  }
  
***************
*** 342,348 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
  }
  
  /* Start a new menu pane in menu_items.
--- 346,352 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qquote);
  }
  
  /* Start a new menu pane in menu_items.
***************
*** 357,365 ****
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
--- 361,369 ----
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   ASET (menu_items, menu_items_used++, Qt);
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, prefix_vec);
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
***************
*** 377,390 ****
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = enable;
!   XVECTOR (menu_items)->contents[menu_items_used++] = key;
!   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
!   XVECTOR (menu_items)->contents[menu_items_used++] = def;
!   XVECTOR (menu_items)->contents[menu_items_used++] = type;
!   XVECTOR (menu_items)->contents[menu_items_used++] = selected;
!   XVECTOR (menu_items)->contents[menu_items_used++] = help;
  }
  \f
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
--- 381,394 ----
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, enable);
!   ASET (menu_items, menu_items_used++, key);
!   ASET (menu_items, menu_items_used++, equiv);
!   ASET (menu_items, menu_items_used++, def);
!   ASET (menu_items, menu_items_used++, type);
!   ASET (menu_items, menu_items_used++, selected);
!   ASET (menu_items, menu_items_used++, help);
  }
  \f
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
***************
*** 450,462 ****
        else if (VECTORP (item))
  	{
  	  /* Loop over the char values represented in the vector.  */
! 	  int len = XVECTOR (item)->size;
  	  int c;
  	  for (c = 0; c < len; c++)
  	    {
  	      Lisp_Object character;
  	      XSETFASTINT (character, c);
! 	      single_menu_item (character, XVECTOR (item)->contents[c],
  				&pending_maps, notreal, maxdepth);
  	    }
  	}
--- 454,466 ----
        else if (VECTORP (item))
  	{
  	  /* Loop over the char values represented in the vector.  */
! 	  int len = ASIZE (item);
  	  int c;
  	  for (c = 0; c < len; c++)
  	    {
  	      Lisp_Object character;
  	      XSETFASTINT (character, c);
! 	      single_menu_item (character, AREF (item, c),
  				&pending_maps, notreal, maxdepth);
  	    }
  	}
***************
*** 504,510 ****
    if (!res)
      return;			/* Not a menu item.  */
  
!   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
    
    if (notreal)
      {
--- 508,514 ----
    if (!res)
      return;			/* Not a menu item.  */
  
!   map = AREF (item_properties, ITEM_PROPERTY_MAP);
    
    if (notreal)
      {
***************
*** 515,522 ****
        return;
      }
  
!   enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
!   item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
--- 519,526 ----
        return;
      }
  
!   enabled = AREF (item_properties, ITEM_PROPERTY_ENABLE);
!   item_string = AREF (item_properties, ITEM_PROPERTY_NAME); 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
***************
*** 528,538 ****
      }
  
    push_menu_item (item_string, enabled, key,
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
--- 532,542 ----
      }
  
    push_menu_item (item_string, enabled, key,
! 		  AREF (item_properties, ITEM_PROPERTY_DEF),
! 		  AREF (item_properties, ITEM_PROPERTY_KEYEQ),
! 		  AREF (item_properties, ITEM_PROPERTY_TYPE),
!                   AREF (item_properties, ITEM_PROPERTY_SELECTED),
!                   AREF (item_properties, ITEM_PROPERTY_HELP));
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
***************
*** 745,751 ****
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
! 	XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
  
        keymaps = 1;
      }
--- 749,755 ----
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
! 	ASET (menu_items, MENU_ITEMS_PANE_NAME, prompt);
  
        keymaps = 1;
      }
***************
*** 777,783 ****
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
! 	XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
  
        keymaps = 1;
      }
--- 781,787 ----
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
! 	ASET (menu_items, MENU_ITEMS_PANE_NAME, title);
  
        keymaps = 1;
      }
***************
*** 800,805 ****
--- 804,819 ----
      }
  
  #ifdef HAVE_MENUS
+   /* If resources from a previous popup menu exist yet, does nothing
+      until the `menu_free_timer' has freed them (see w32fns.c).
+   */
+   if (current_popup_menu)
+     {
+       discard_menu_items ();
+       UNGCPRO;
+       return Qnil;
+     }    
+   
    /* Display them in a menu.  */
    BLOCK_INPUT;
  
***************
*** 808,816 ****
    UNBLOCK_INPUT;
  
    discard_menu_items ();
  
    UNGCPRO;
- #endif /* HAVE_MENUS */
  
    if (error_name) error (error_name);
    return selection;
--- 822,830 ----
    UNBLOCK_INPUT;
  
    discard_menu_items ();
+ #endif /* HAVE_MENUS */
  
    UNGCPRO;
  
    if (error_name) error (error_name);
    return selection;
***************
*** 981,1005 ****
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (XVECTOR (vector)->contents[i], Qnil))
  	{
  	  subprefix_stack[submenu_depth++] = prefix;
  	  prefix = entry;
  	  i++;
  	}
!       else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
  	{
  	  prefix = subprefix_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (XVECTOR (vector)->contents[i], Qt))
  	{
! 	  prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	  i += MENU_ITEMS_PANE_LENGTH;
  	}
        else
  	{
! 	  entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
  	  if ((int) (EMACS_INT) client_data == i)
--- 995,1019 ----
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (AREF (vector, i), Qnil))
  	{
  	  subprefix_stack[submenu_depth++] = prefix;
  	  prefix = entry;
  	  i++;
  	}
!       else if (EQ (AREF (vector, i), Qlambda))
  	{
  	  prefix = subprefix_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (AREF (vector, i), Qt))
  	{
! 	  prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
  	  i += MENU_ITEMS_PANE_LENGTH;
  	}
        else
  	{
! 	  entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
  	  if ((int) (EMACS_INT) client_data == i)
***************
*** 1051,1056 ****
--- 1065,1089 ----
    f->output_data.w32->menubar_active = 0;
  }
  
+ /* Return a local copy of the given input string STR.
+    Does nothing if STR is 0.
+    
+    It is necessary to use safe local copy of string data stored in
+    widget_value because the data part of Lisp strings can be relocated
+    when the GC compacts string storage.  Even when the base string
+    Lisp_Object is protected!  */
+ char *
+ local_string (const char *str)
+ {
+   if (str)
+     {
+       char *clone = (char *) local_alloc (strlen (str) + 1);
+       strcpy (clone, str);
+       return clone;
+     }
+   return 0;
+ }
+ 
  /* Allocate a widget_value, blocking input.  */
  
  widget_value *
***************
*** 1075,1081 ****
       widget_value *wv;
  {
    if (! wv) return;
! 
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
--- 1108,1118 ----
       widget_value *wv;
  {
    if (! wv) return;
!   
!   local_free (wv->name);
!   local_free (wv->value);
!   local_free (wv->key);
!   
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
***************
*** 1148,1154 ****
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
    wv = xmalloc_widget_value ();
!   wv->name = "menu";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1185,1191 ----
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menu");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1164,1203 ****
    i = previous_items;
    while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
  	  prev_wv = 0;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
  	  char *pane_string;
  
! 	  pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
! 	  prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  
  #ifndef HAVE_MULTILINGUAL_MENU
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
--- 1201,1240 ----
    i = previous_items;
    while (i < menu_items_used)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
  	  prev_wv = 0;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
  	i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
  	  char *pane_string;
  
! 	  pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
! 	  prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  
  #ifndef HAVE_MULTILINGUAL_MENU
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
***************
*** 1222,1227 ****
--- 1259,1265 ----
  		 This is a kludge, but this isn't worth more time.  */
  	      if (!NILP (prefix) && wv->name[0] == '@')
  		wv->name++;
+               wv->name = local_string (wv->name);
  	      wv->value = 0;
  	      wv->enabled = 1;
  	      wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1249,1261 ****
  	  if (STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
  	    }
  
  	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
  	    {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1287,1299 ----
  	  if (STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
  	    }
  
  	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
  	    {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1265,1273 ****
  	  else
  	    save_wv->contents = wv;
  
! 	  wv->name = (char *) SDATA (item_name);
  	  if (!NILP (descrip))
! 	    wv->key = (char *) SDATA (descrip);
  	  wv->value = 0;
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
--- 1303,1311 ----
  	  else
  	    save_wv->contents = wv;
  
! 	  wv->name = local_string ((char *) SDATA (item_name));
  	  if (!NILP (descrip))
! 	    wv->key = local_string ((char *) SDATA (descrip));
  	  wv->value = 0;
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
***************
*** 1334,1340 ****
      deep_p = 1;
  
    wv = xmalloc_widget_value ();
!   wv->name = "menubar";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1372,1378 ----
      deep_p = 1;
  
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menubar");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1395,1407 ****
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
        init_menu_items ();
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object key, string, maps;
  
! 	  key = XVECTOR (items)->contents[i];
! 	  string = XVECTOR (items)->contents[i + 1];
! 	  maps = XVECTOR (items)->contents[i + 2];
  	  if (NILP (string))
  	    break;
  
--- 1433,1445 ----
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
        init_menu_items ();
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object key, string, maps;
  
! 	  key = AREF (items, i);
! 	  string = AREF (items, i + 1);
! 	  maps = AREF (items, i + 2);
  	  if (NILP (string))
  	    break;
  
***************
*** 1426,1432 ****
  
        for (i = 0; i < previous_menu_items_used; i++)
  	if (menu_items_used == i
! 	    || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
  	  break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
  	{
--- 1464,1470 ----
  
        for (i = 0; i < previous_menu_items_used; i++)
  	if (menu_items_used == i
! 	    || (!EQ (previous_items[i], AREF (menu_items, i))))
  	  break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
  	{
***************
*** 1442,1454 ****
  	 Windows takes care of this for normal string items, but
  	 not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object string;
! 	  string = XVECTOR (items)->contents[i + 1];
  	  if (NILP (string))
  	    break;
! 	  wv->name = (char *) SDATA (string);
  	  wv = wv->next;
  	}
  
--- 1480,1492 ----
  	 Windows takes care of this for normal string items, but
  	 not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object string;
! 	  string = AREF (items, i + 1);
  	  if (NILP (string))
  	    break;
! 	  wv->name = local_string ((char *) SDATA (string));
  	  wv = wv->next;
  	}
  
***************
*** 1462,1477 ****
  	 just the top level menu bar strings.  */
  
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object string;
  
! 	  string = XVECTOR (items)->contents[i + 1];
  	  if (NILP (string))
  	    break;
  
  	  wv = xmalloc_widget_value ();
! 	  wv->name = (char *) SDATA (string);
  	  wv->value = 0;
  	  wv->enabled = 1;
  	  wv->button_type = BUTTON_TYPE_NONE;
--- 1500,1515 ----
  	 just the top level menu bar strings.  */
  
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object string;
  
! 	  string = AREF (items, i + 1);
  	  if (NILP (string))
  	    break;
  
  	  wv = xmalloc_widget_value ();
! 	  wv->name = local_string ((char *) SDATA (string));
  	  wv->value = 0;
  	  wv->enabled = 1;
  	  wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1613,1619 ****
    /* Create a tree of widget_value objects
       representing the panes and their items.  */
    wv = xmalloc_widget_value ();
!   wv->name = "menu";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1651,1657 ----
    /* Create a tree of widget_value objects
       representing the panes and their items.  */
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menu");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1625,1631 ****
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
--- 1663,1669 ----
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
***************
*** 1633,1653 ****
  	  first_pane = 1;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  first_pane = 0;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
--- 1671,1691 ----
  	  first_pane = 1;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  first_pane = 0;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
  	i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
***************
*** 1658,1664 ****
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
--- 1696,1702 ----
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
***************
*** 1681,1686 ****
--- 1719,1725 ----
  	      wv->name = pane_string;
  	      if (keymaps && !NILP (prefix))
  		wv->name++;
+               wv->name = local_string (wv->name);
  	      wv->value = 0;
  	      wv->enabled = 1;
  	      wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1713,1724 ****
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
  	    }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1752,1763 ----
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
  	    }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1727,1735 ****
  	    prev_wv->next = wv;
  	  else 
  	    save_wv->contents = wv;
! 	  wv->name = (char *) SDATA (item_name);
  	  if (!NILP (descrip))
! 	    wv->key = (char *) SDATA (descrip);
  	  wv->value = 0;
  	  /* Use the contents index as call_data, since we are
               restricted to 16-bits.  */
--- 1766,1774 ----
  	    prev_wv->next = wv;
  	  else 
  	    save_wv->contents = wv;
! 	  wv->name = local_string ((char *) SDATA (item_name));
  	  if (!NILP (descrip))
! 	    wv->key = local_string ((char *) SDATA (descrip));
  	  wv->value = 0;
  	  /* Use the contents index as call_data, since we are
               restricted to 16-bits.  */
***************
*** 1765,1771 ****
  
        /* Maybe replace this separator with a bitmap or owner-draw item
  	 so that it looks better.  Having two separators looks odd.  */
!       wv_sep->name = "--";
        wv_sep->next = first_wv->contents;
        wv_sep->help = Qnil;
  
--- 1804,1810 ----
  
        /* Maybe replace this separator with a bitmap or owner-draw item
  	 so that it looks better.  Having two separators looks odd.  */
!       wv_sep->name = local_string ("--");
        wv_sep->next = first_wv->contents;
        wv_sep->help = Qnil;
  
***************
*** 1773,1779 ****
        if (STRING_MULTIBYTE (title))
  	title = ENCODE_SYSTEM (title);
  #endif
!       wv_title->name = (char *) SDATA (title);
        wv_title->enabled = TRUE;
        wv_title->title = TRUE;
        wv_title->button_type = BUTTON_TYPE_NONE;
--- 1812,1818 ----
        if (STRING_MULTIBYTE (title))
  	title = ENCODE_SYSTEM (title);
  #endif
!       wv_title->name = local_string ((char *) SDATA (title));
        wv_title->enabled = TRUE;
        wv_title->title = TRUE;
        wv_title->button_type = BUTTON_TYPE_NONE;
***************
*** 1818,1848 ****
        i = 0;
        while (i < menu_items_used)
  	{
! 	  if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	    {
  	      subprefix_stack[submenu_depth++] = prefix;
  	      prefix = entry;
  	      i++;
  	    }
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	    {
  	      prefix = subprefix_stack[--submenu_depth];
  	      i++;
  	    }
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	    {
! 	      prefix
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  /* Ignore a nil in the item list.
  	     It's meaningful only for dialog boxes.  */
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	    i += 1;
  	  else
  	    {
! 	      entry
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
--- 1857,1885 ----
        i = 0;
        while (i < menu_items_used)
  	{
! 	  if (EQ (AREF (menu_items, i), Qnil))
  	    {
  	      subprefix_stack[submenu_depth++] = prefix;
  	      prefix = entry;
  	      i++;
  	    }
! 	  else if (EQ (AREF (menu_items, i), Qlambda))
  	    {
  	      prefix = subprefix_stack[--submenu_depth];
  	      i++;
  	    }
! 	  else if (EQ (AREF (menu_items, i), Qt))
  	    {
! 	      prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  /* Ignore a nil in the item list.
  	     It's meaningful only for dialog boxes.  */
! 	  else if (EQ (AREF (menu_items, i), Qquote))
  	    i += 1;
  	  else
  	    {
! 	      entry	= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
***************
*** 1903,1910 ****
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
!     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
      pane_string = (NILP (pane_name)
  		   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
--- 1940,1947 ----
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
!     prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
      pane_string = (NILP (pane_name)
  		   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
***************
*** 1924,1934 ****
  	/* Create a new item within current pane.  */
  	Lisp_Object item_name, enable, descrip, help;
  
! 	item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
! 	enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
! 	descrip
! 	  = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
!         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
  	
  	if (NILP (item_name))
  	  {
--- 1961,1970 ----
  	/* Create a new item within current pane.  */
  	Lisp_Object item_name, enable, descrip, help;
  
! 	item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
! 	enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
! 	descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
!         help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
  	
  	if (NILP (item_name))
  	  {
***************
*** 1957,1963 ****
  	if (!NILP (descrip))
  	  wv->key = (char *) SDATA (descrip);
  	wv->value = (char *) SDATA (item_name);
! 	wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
  	wv->enabled = !NILP (enable);
  	wv->help = Qnil;
  	prev_wv = wv;
--- 1993,1999 ----
  	if (!NILP (descrip))
  	  wv->key = (char *) SDATA (descrip);
  	wv->value = (char *) SDATA (item_name);
! 	wv->call_data = (void *) &AREF (menu_items, i);
  	wv->enabled = !NILP (enable);
  	wv->help = Qnil;
  	prev_wv = wv;
***************
*** 2027,2042 ****
  	{
  	  Lisp_Object entry;
  
! 	  if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	    {
! 	      prefix
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  else
  	    {
! 	      entry
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
--- 2063,2076 ----
  	{
  	  Lisp_Object entry;
  
! 	  if (EQ (AREF (menu_items, i), Qt))
  	    {
! 	      prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  else
  	    {
! 	      entry	= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
***************
*** 2117,2127 ****
  	     we can't deallocate the memory otherwise.  */
  	  if (get_menu_item_info)
  	    {
! 	      out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
  #ifdef MENU_DEBUG
! 	      DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
  #endif
- 	      strcpy (out_string, wv->name);
  	      fuFlags = MF_OWNERDRAW | MF_DISABLED;
  	    }
  	  else
--- 2151,2160 ----
  	     we can't deallocate the memory otherwise.  */
  	  if (get_menu_item_info)
  	    {
! 	      out_string = local_string (wv->name);
  #ifdef MENU_DEBUG
! 	      DebPrint ("Menu: allocing %ld for owner-draw", out_string);
  #endif
  	      fuFlags = MF_OWNERDRAW | MF_DISABLED;
  	    }
  	  else
***************
*** 2277,2283 ****
  #ifdef MENU_DEBUG
  	  DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
! 	  LocalFree (info.dwItemData);
  	}
  
        /* Recurse down submenus.  */
--- 2310,2316 ----
  #ifdef MENU_DEBUG
  	  DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
! 	  local_free (info.dwItemData);
  	}
  
        /* Recurse down submenus.  */

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-28 16:56       ` David Ponce
@ 2002-07-29 17:30         ` Richard Stallman
  2002-07-29 18:16           ` David Ponce
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Stallman @ 2002-07-29 17:30 UTC (permalink / raw)
  Cc: emacs-devel

Is this comment in w32menu.c inaccurate?

      /* Now GC cannot happen during the lifetime of the widget_value,
	 so it's safe to store data from a Lisp_String, as long as
	 local copies are made when the actual menu is created.
	 Windows takes care of this for normal string items, but
	 not for owner-drawn items or additional item-info.  */

If it is inaccurate, why is that?  How is it that GC happens in
between creation of the widget value and its use in add_menu_item?
Note that GC ought to be inhibited within set_frame_menubar
from this line

      inhibit_garbage_collection ();

to this line

      unbind_to (specpdl_count, Qnil);

Does the GC happen inside that range, or after?
Either way, it's a bug; the question is what bug.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-29 17:30         ` Richard Stallman
@ 2002-07-29 18:16           ` David Ponce
  2002-07-30 18:46             ` Richard Stallman
  0 siblings, 1 reply; 13+ messages in thread
From: David Ponce @ 2002-07-29 18:16 UTC (permalink / raw)
  Cc: emacs-devel

>
>
>Is this comment in w32menu.c inaccurate?
>
>      /* Now GC cannot happen during the lifetime of the widget_value,
>	 so it's safe to store data from a Lisp_String, as long as
>	 local copies are made when the actual menu is created.
>	 Windows takes care of this for normal string items, but
>	 not for owner-drawn items or additional item-info.  */
>
Yes I think it is inaccurate.
IMO, GC cannot happen after the build of the widget_value tree is completed.

>If it is inaccurate, why is that?  How is it that GC happens in
>between creation of the widget value and its use in add_menu_item?
>Note that GC ought to be inhibited within set_frame_menubar
>from this line
>
>      inhibit_garbage_collection ();
>
>to this line
>
>      unbind_to (specpdl_count, Qnil);
>
>Does the GC happen inside that range, or after?
>Either way, it's a bug; the question is what bug.
>
Yes GC seems to happen inside that range when building the widget_value 
tree.
When it happens it can change the address of strings (when compacting 
the string pool)
that are stored in already allocated widget_values.

I suppose it explains this comment

 "/* Don't set wv->name here; GC during the loop might relocate it.  */"

 which appears inside that range.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
@ 2002-07-30 11:28 David PONCE
  0 siblings, 0 replies; 13+ messages in thread
From: David PONCE @ 2002-07-30 11:28 UTC (permalink / raw)
  Cc: emacs-devel

Richard,

I can confirm that GC is the cause of the problem.  I printed
messages before, after, and in the middle of the loop that build the
widget_value tree and when entering GC.  Here is a snippet of printed
result that clearly shows that GC happened while running
single_submenu:

[...]
w32menu.set_frame_menubar before init_menu_items consing/threshold(375580/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(375580/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(376568/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(376568/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(466128/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(466128/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(485808/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(485808/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(485920/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(485920/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(486276/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(486276/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(501404/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(501404/134217727)
*** GC entered consing/threshold(509952/10000000)
*** GC entered consing/threshold(872/10000000)
w32menu.set_frame_menubar after single_submenu consing/threshold(6444/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(6444/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(7120/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(7120/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(10568/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(10568/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(24800/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(24800/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(39056/134217727)
w32menu.set_frame_menubar before single_submenu consing/threshold(39056/134217727)
w32menu.set_frame_menubar after single_submenu consing/threshold(100504/134217727)
w32menu.set_frame_menubar after finish_menu_items consing/threshold(100504/134217727)
*** GC entered consing/threshold(101352/10000000)
[...]

In fact 10000000 is the `gc-cons-threshold' value that the Semantic
parser locally uses to speed up things.  The parser is called from
`menu-bar-update-hook' to produce the parse tree used to build the
imenu index.  And can be called too via an idle timer to re-parse the
buffer when necessary.  Also the parser explicitly calls
`garbage-collect' to free memory before it locally binds
`gc-cons-threshold'.  Maybe the parser hook or timer are
asynchronously activated while building the widget_value tree?

IMO it is definitively a bug in Emacs to consider that the range of
code that builds the menu tree is GC safe, because user's Lisp code
can call `garbage-collect' or re-bind `gc-cons-threshold' to a value
lower than the maximum one set by `inhibit_garbage_collection' to
inhibit GC.  As Lisp strings data can be relocated even if the
Lisp_Object is protected, it is only safe to store string data
locations when it is really sure that GC can't happen.

My proposed patch to w32menu.c make widget_value insensible to GC
because it only contains pointers to safe strings, copied in local
heap.  The counterpart is a little overhead.  From what I observed, I
didn't noticed a significant slow down when using menus.

Maybe another possible solution could be that
`inhibit_garbage_collection' uses a flag to block GC?  By default it
would be t to allow GC and could be set to nil to really disable GC.
Something like this:

(let ((inhibit_garbage_collection nil))
  (garbage_collect) ;; Does nothing!
 )

I don't know if a such flag should be exported to Lisp.  Perhaps its
use would be dangerous!

David

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-29 18:16           ` David Ponce
@ 2002-07-30 18:46             ` Richard Stallman
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Stallman @ 2002-07-30 18:46 UTC (permalink / raw)
  Cc: emacs-devel

    >Does the GC happen inside that range, or after?
    >Either way, it's a bug; the question is what bug.
    >
    Yes GC seems to happen inside that range when building the widget_value 
    tree.

Please show precisely how GC happens inside there.  Then we can fix it.
A backtrace from GC within that area may be enough info.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
       [not found] <3D2A791A00A0862A@mel-rta9.wanadoo.fr>
@ 2002-07-31 21:57 ` Richard Stallman
  2002-07-31 22:37   ` David Ponce
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Stallman @ 2002-07-31 21:57 UTC (permalink / raw)
  Cc: emacs-devel

I figured out how Lisp code was getting called during that loop.
xmenu.c had the same bug, so I fixed it there.

Now we need a Windows hacker to adapt the same fix to w32menu.c.
Perhaps macmenu.c needs the same change.

Thanks for figuring this out.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
  2002-07-31 21:57 ` Richard Stallman
@ 2002-07-31 22:37   ` David Ponce
  0 siblings, 0 replies; 13+ messages in thread
From: David Ponce @ 2002-07-31 22:37 UTC (permalink / raw)
  Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1560 bytes --]

Richard Stallman wrote:

>I figured out how Lisp code was getting called during that loop.
>xmenu.c had the same bug, so I fixed it there.
>
>Now we need a Windows hacker to adapt the same fix to w32menu.c.
>Perhaps macmenu.c needs the same change.
>
>Thanks for figuring this out.
>
>
Hi Richard,

I adapted your changes from xmenu.c to the version of w32menu.c where
I fixed another bug with popup menu, and generalized use of the macros
AREF, ASET, ASIZE, to access vectors.  Attached you will find a new
diff.  The change log is at end.

I currently use this new version and can confirm that you fixed the bug
:-)

Thank you very much for your support!
David

------------ Change Log:

(local_heap, local_alloc, local_free): New macros.
(malloc_widget_value, free_widget_value)
(w32_free_submenu_strings): Use them.

(push_submenu_start, push_submenu_end, push_left_right_boundary)
(push_menu_pane, push_menu_item, single_keymap_panes)
(single_menu_item, Fx_popup_menu, menubar_selection_callback)
(single_submenu, set_frame_menubar)
(w32_menu_show, w32_dialog_show): Use AREF, ASET, ASIZE.

(Fx_popup_menu):  Don't show pop up menu until preceding one is
actually cleaned up.  Moved UNGCPRO outside #ifdef HAVE_MENUS block.

Changes adapted from xmenu.c

(set_frame_menubar): First parse all submenus,
then make widget_value trees from them.
Don't allocate any widget_value objects
until we are done with the parsing.
(parse_single_submenu): New function.
(digest_single_submenu): New function.
(single_submenu): Function deleted, replaced by those two.


[-- Attachment #2: w32menu.patch --]
[-- Type: text/x-patch, Size: 31663 bytes --]

*** w32menu.c.ori	Mon Jul 15 10:48:32 2002
--- w32menu.c	Wed Jul 31 21:22:29 2002
***************
*** 112,120 ****
  #endif
  } widget_value;
  
! /* LocalAlloc/Free is a reasonably good allocator.  */
! #define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof (widget_value))
! #define free_widget_value(wv) LocalFree (wv)
  
  /******************************************************************/
  
--- 112,124 ----
  #endif
  } widget_value;
  
! /* Local memory management */
! #define local_heap (GetProcessHeap ())
! #define local_alloc(n) (HeapAlloc (local_heap, HEAP_ZERO_MEMORY, (n)))
! #define local_free(p) (HeapFree (local_heap, 0, ((LPVOID) (p))))
! 
! #define malloc_widget_value() ((widget_value *) local_alloc (sizeof (widget_value)))
! #define free_widget_value(wv) (local_free ((wv)))
  
  /******************************************************************/
  
***************
*** 318,324 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
    menu_items_submenu_depth++;
  }
  
--- 322,328 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qnil);
    menu_items_submenu_depth++;
  }
  
***************
*** 330,336 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
    menu_items_submenu_depth--;
  }
  
--- 334,340 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qlambda);
    menu_items_submenu_depth--;
  }
  
***************
*** 342,348 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
  }
  
  /* Start a new menu pane in menu_items.
--- 346,352 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qquote);
  }
  
  /* Start a new menu pane in menu_items.
***************
*** 357,365 ****
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
--- 361,369 ----
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   ASET (menu_items, menu_items_used++, Qt);
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, prefix_vec);
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
***************
*** 377,390 ****
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = enable;
!   XVECTOR (menu_items)->contents[menu_items_used++] = key;
!   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
!   XVECTOR (menu_items)->contents[menu_items_used++] = def;
!   XVECTOR (menu_items)->contents[menu_items_used++] = type;
!   XVECTOR (menu_items)->contents[menu_items_used++] = selected;
!   XVECTOR (menu_items)->contents[menu_items_used++] = help;
  }
  \f
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
--- 381,394 ----
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, enable);
!   ASET (menu_items, menu_items_used++, key);
!   ASET (menu_items, menu_items_used++, equiv);
!   ASET (menu_items, menu_items_used++, def);
!   ASET (menu_items, menu_items_used++, type);
!   ASET (menu_items, menu_items_used++, selected);
!   ASET (menu_items, menu_items_used++, help);
  }
  \f
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
***************
*** 450,462 ****
        else if (VECTORP (item))
  	{
  	  /* Loop over the char values represented in the vector.  */
! 	  int len = XVECTOR (item)->size;
  	  int c;
  	  for (c = 0; c < len; c++)
  	    {
  	      Lisp_Object character;
  	      XSETFASTINT (character, c);
! 	      single_menu_item (character, XVECTOR (item)->contents[c],
  				&pending_maps, notreal, maxdepth);
  	    }
  	}
--- 454,466 ----
        else if (VECTORP (item))
  	{
  	  /* Loop over the char values represented in the vector.  */
! 	  int len = ASIZE (item);
  	  int c;
  	  for (c = 0; c < len; c++)
  	    {
  	      Lisp_Object character;
  	      XSETFASTINT (character, c);
! 	      single_menu_item (character, AREF (item, c),
  				&pending_maps, notreal, maxdepth);
  	    }
  	}
***************
*** 504,510 ****
    if (!res)
      return;			/* Not a menu item.  */
  
!   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
    
    if (notreal)
      {
--- 508,514 ----
    if (!res)
      return;			/* Not a menu item.  */
  
!   map = AREF (item_properties, ITEM_PROPERTY_MAP);
    
    if (notreal)
      {
***************
*** 515,522 ****
        return;
      }
  
!   enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
!   item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
--- 519,526 ----
        return;
      }
  
!   enabled = AREF (item_properties, ITEM_PROPERTY_ENABLE);
!   item_string = AREF (item_properties, ITEM_PROPERTY_NAME); 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
***************
*** 528,538 ****
      }
  
    push_menu_item (item_string, enabled, key,
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
! 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
--- 532,542 ----
      }
  
    push_menu_item (item_string, enabled, key,
! 		  AREF (item_properties, ITEM_PROPERTY_DEF),
! 		  AREF (item_properties, ITEM_PROPERTY_KEYEQ),
! 		  AREF (item_properties, ITEM_PROPERTY_TYPE),
!                   AREF (item_properties, ITEM_PROPERTY_SELECTED),
!                   AREF (item_properties, ITEM_PROPERTY_HELP));
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
***************
*** 745,751 ****
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
! 	XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
  
        keymaps = 1;
      }
--- 749,755 ----
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
! 	ASET (menu_items, MENU_ITEMS_PANE_NAME, prompt);
  
        keymaps = 1;
      }
***************
*** 777,783 ****
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
! 	XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
  
        keymaps = 1;
      }
--- 781,787 ----
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
! 	ASET (menu_items, MENU_ITEMS_PANE_NAME, title);
  
        keymaps = 1;
      }
***************
*** 800,805 ****
--- 804,819 ----
      }
  
  #ifdef HAVE_MENUS
+   /* If resources from a previous popup menu exist yet, does nothing
+      until the `menu_free_timer' has freed them (see w32fns.c).
+   */
+   if (current_popup_menu)
+     {
+       discard_menu_items ();
+       UNGCPRO;
+       return Qnil;
+     }    
+   
    /* Display them in a menu.  */
    BLOCK_INPUT;
  
***************
*** 808,816 ****
    UNBLOCK_INPUT;
  
    discard_menu_items ();
  
    UNGCPRO;
- #endif /* HAVE_MENUS */
  
    if (error_name) error (error_name);
    return selection;
--- 822,830 ----
    UNBLOCK_INPUT;
  
    discard_menu_items ();
+ #endif /* HAVE_MENUS */
  
    UNGCPRO;
  
    if (error_name) error (error_name);
    return selection;
***************
*** 981,1005 ****
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (XVECTOR (vector)->contents[i], Qnil))
  	{
  	  subprefix_stack[submenu_depth++] = prefix;
  	  prefix = entry;
  	  i++;
  	}
!       else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
  	{
  	  prefix = subprefix_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (XVECTOR (vector)->contents[i], Qt))
  	{
! 	  prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	  i += MENU_ITEMS_PANE_LENGTH;
  	}
        else
  	{
! 	  entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
  	  if ((int) (EMACS_INT) client_data == i)
--- 995,1019 ----
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (AREF (vector, i), Qnil))
  	{
  	  subprefix_stack[submenu_depth++] = prefix;
  	  prefix = entry;
  	  i++;
  	}
!       else if (EQ (AREF (vector, i), Qlambda))
  	{
  	  prefix = subprefix_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (AREF (vector, i), Qt))
  	{
! 	  prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
  	  i += MENU_ITEMS_PANE_LENGTH;
  	}
        else
  	{
! 	  entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
  	  /* The EMACS_INT cast avoids a warning.  There's no problem
  	     as long as pointers have enough bits to hold small integers.  */
  	  if ((int) (EMACS_INT) client_data == i)
***************
*** 1075,1081 ****
       widget_value *wv;
  {
    if (! wv) return;
! 
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
--- 1089,1095 ----
       widget_value *wv;
  {
    if (! wv) return;
!   
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
***************
*** 1093,1114 ****
    UNBLOCK_INPUT;
  }
  \f
! /* Return a tree of widget_value structures for a menu bar item
     whose event type is ITEM_KEY (with string ITEM_NAME)
     and whose contents come from the list of keymaps MAPS.  */
  
! static widget_value *
! single_submenu (item_key, item_name, maps)
       Lisp_Object item_key, item_name, maps;
  {
-   widget_value *wv, *prev_wv, *save_wv, *first_wv;
-   int i;
-   int submenu_depth = 0;
    Lisp_Object length;
    int len;
    Lisp_Object *mapvec;
!   widget_value **submenu_stack;
!   int previous_items = menu_items_used;
    int top_level_items = 0;
  
    length = Flength (maps);
--- 1107,1124 ----
    UNBLOCK_INPUT;
  }
  \f
! /* Set up data i menu_items for a menu bar item
     whose event type is ITEM_KEY (with string ITEM_NAME)
     and whose contents come from the list of keymaps MAPS.  */
  
! static int
! parse_single_submenu (item_key, item_name, maps)
       Lisp_Object item_key, item_name, maps;
  {
    Lisp_Object length;
    int len;
    Lisp_Object *mapvec;
!   int i;
    int top_level_items = 0;
  
    length = Flength (maps);
***************
*** 1122,1129 ****
        maps = Fcdr (maps);
      }
  
-   menu_items_n_panes = 0;
- 
    /* Loop over the given keymaps, making a pane for each map.
       But don't make a pane that is empty--ignore that map instead.  */
    for (i = 0; i < len; i++)
--- 1132,1137 ----
***************
*** 1141,1149 ****
        else
  	single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
      }
  
!   /* Create a tree of widget_value objects
!      representing the panes and their items.  */
  
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
--- 1149,1171 ----
        else
  	single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
      }
+   
+   return top_level_items;
+ }
  
! 
! /* Create a tree of widget_value objects
!    representing the panes and items
!    in menu_items starting at index START, up to index END.  */
! 
! static widget_value *
! digest_single_submenu (start, end, top_level_items)
!      int start, end;
! {
!   widget_value *wv, *prev_wv, *save_wv, *first_wv;
!   int i;
!   int submenu_depth = 0;
!   widget_value **submenu_stack;
  
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
***************
*** 1161,1203 ****
       and construct a tree of widget_value objects.
       Ignore the panes and items made by previous calls to
       single_submenu, even though those are also in menu_items.  */
!   i = previous_items;
!   while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
  	  prev_wv = 0;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
  	  char *pane_string;
  
! 	  pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
! 	  prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  
  #ifndef HAVE_MULTILINGUAL_MENU
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
--- 1183,1225 ----
       and construct a tree of widget_value objects.
       Ignore the panes and items made by previous calls to
       single_submenu, even though those are also in menu_items.  */
!   i = start;
!   while (i < end)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
  	  prev_wv = 0;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
  	i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
  	  char *pane_string;
  
! 	  pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
! 	  prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  
  #ifndef HAVE_MULTILINGUAL_MENU
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
***************
*** 1249,1261 ****
  	  if (STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
  	    }
  
  	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
  	    {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1271,1283 ----
  	  if (STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
  	    }
  
  	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
  	    {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1320,1326 ****
    HMENU menubar_widget = f->output_data.w32->menubar_widget;
    Lisp_Object items;
    widget_value *wv, *first_wv, *prev_wv = 0;
!   int i;
  
    /* We must not change the menubar when actually in use.  */
    if (f->output_data.w32->menubar_active)
--- 1342,1350 ----
    HMENU menubar_widget = f->output_data.w32->menubar_widget;
    Lisp_Object items;
    widget_value *wv, *first_wv, *prev_wv = 0;
!   int i, last_i;
!   int *submenu_start, *submenu_end;
!   int *submenu_top_level_items;
  
    /* We must not change the menubar when actually in use.  */
    if (f->output_data.w32->menubar_active)
***************
*** 1333,1346 ****
    else if (pending_menu_activation && !deep_p)
      deep_p = 1;
  
-   wv = xmalloc_widget_value ();
-   wv->name = "menubar";
-   wv->value = 0;
-   wv->enabled = 1;
-   wv->button_type = BUTTON_TYPE_NONE;
-   wv->help = Qnil;
-   first_wv = wv;
- 
    if (deep_p)
      {
        /* Make a widget-value tree representing the entire menu trees.  */
--- 1357,1362 ----
***************
*** 1384,1411 ****
  
        items = FRAME_MENU_BAR_ITEMS (f);
  
-       inhibit_garbage_collection ();
- 
        /* Save the frame's previous menu bar contents data.  */
        if (previous_menu_items_used)
  	bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
  	       previous_menu_items_used * sizeof (Lisp_Object));
  
!       /* Fill in the current menu bar contents.  */
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
        init_menu_items ();
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object key, string, maps;
  
! 	  key = XVECTOR (items)->contents[i];
! 	  string = XVECTOR (items)->contents[i + 1];
! 	  maps = XVECTOR (items)->contents[i + 2];
  	  if (NILP (string))
  	    break;
  
! 	  wv = single_submenu (key, string, maps);
  	  if (prev_wv) 
  	    prev_wv->next = wv;
  	  else
--- 1400,1457 ----
  
        items = FRAME_MENU_BAR_ITEMS (f);
  
        /* Save the frame's previous menu bar contents data.  */
        if (previous_menu_items_used)
  	bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
  	       previous_menu_items_used * sizeof (Lisp_Object));
  
!       /* Fill in menu_items with the current menu bar contents.
! 	 This can evaluate Lisp code.  */
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
+       submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+       submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+       submenu_top_level_items
+ 	= (int *) alloca (XVECTOR (items)->size * sizeof (int *));
        init_menu_items ();
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object key, string, maps;
  
! 	  last_i = i;
! 
! 	  key = AREF (items, i);
! 	  string = AREF (items, i + 1);
! 	  maps = AREF (items, i + 2);
  	  if (NILP (string))
  	    break;
  
! 	  submenu_start[i] = menu_items_used;
! 
! 	  menu_items_n_panes = 0;
! 	  submenu_top_level_items[i]
! 	    = parse_single_submenu (key, string, maps);
! 
! 	  submenu_end[i] = menu_items_used;
! 	}
! 
!       finish_menu_items ();
! 
!       /* Convert menu_items into widget_value trees
! 	 to display the menu.  This cannot evaluate Lisp code.  */
! 
!       wv = xmalloc_widget_value ();
!       wv->name = "menubar";
!       wv->value = 0;
!       wv->enabled = 1;
!       wv->button_type = BUTTON_TYPE_NONE;
!       wv->help = Qnil;
!       first_wv = wv;
! 
!       for (i = 0; i < last_i; i += 4)
! 	{
! 	  wv = digest_single_submenu (submenu_start[i], submenu_end[i],
! 				      submenu_top_level_items[i]);
  	  if (prev_wv) 
  	    prev_wv->next = wv;
  	  else
***************
*** 1416,1423 ****
  	  prev_wv = wv;
  	}
  
-       finish_menu_items ();
- 
        set_buffer_internal_1 (prev);
        unbind_to (specpdl_count, Qnil);
  
--- 1462,1467 ----
***************
*** 1426,1432 ****
  
        for (i = 0; i < previous_menu_items_used; i++)
  	if (menu_items_used == i
! 	    || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
  	  break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
  	{
--- 1470,1476 ----
  
        for (i = 0; i < previous_menu_items_used; i++)
  	if (menu_items_used == i
! 	    || (!EQ (previous_items[i], AREF (menu_items, i))))
  	  break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
  	{
***************
*** 1442,1451 ****
  	 Windows takes care of this for normal string items, but
  	 not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object string;
! 	  string = XVECTOR (items)->contents[i + 1];
  	  if (NILP (string))
  	    break;
  	  wv->name = (char *) SDATA (string);
--- 1486,1495 ----
  	 Windows takes care of this for normal string items, but
  	 not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object string;
! 	  string = AREF (items, i + 1);
  	  if (NILP (string))
  	    break;
  	  wv->name = (char *) SDATA (string);
***************
*** 1461,1472 ****
        /* Make a widget-value tree containing
  	 just the top level menu bar strings.  */
  
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
  	{
  	  Lisp_Object string;
  
! 	  string = XVECTOR (items)->contents[i + 1];
  	  if (NILP (string))
  	    break;
  
--- 1505,1524 ----
        /* Make a widget-value tree containing
  	 just the top level menu bar strings.  */
  
+       wv = xmalloc_widget_value ();
+       wv->name = "menubar";
+       wv->value = 0;
+       wv->enabled = 1;
+       wv->button_type = BUTTON_TYPE_NONE;
+       wv->help = Qnil;
+       first_wv = wv;
+ 
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < ASIZE (items); i += 4)
  	{
  	  Lisp_Object string;
  
! 	  string = AREF (items, i + 1);
  	  if (NILP (string))
  	    break;
  
***************
*** 1625,1631 ****
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
--- 1677,1683 ----
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
  	{
  	  submenu_stack[submenu_depth++] = save_wv;
  	  save_wv = prev_wv;
***************
*** 1633,1653 ****
  	  first_pane = 1;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  first_pane = 0;
  	  i++;
  	}
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
--- 1685,1705 ----
  	  first_pane = 1;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qlambda))
  	{
  	  prev_wv = save_wv;
  	  save_wv = submenu_stack[--submenu_depth];
  	  first_pane = 0;
  	  i++;
  	}
!       else if (EQ (AREF (menu_items, i), Qt)
  	       && submenu_depth != 0)
  	i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
  	 It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
  	i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
  	{
  	  /* Create a new pane.  */
  	  Lisp_Object pane_name, prefix;
***************
*** 1658,1664 ****
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
--- 1710,1716 ----
  	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
  	    {
  	      pane_name = ENCODE_SYSTEM (pane_name);
! 	      ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
  	    }
  #endif
  	  pane_string = (NILP (pane_name)
***************
*** 1713,1724 ****
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
  	    }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1765,1776 ----
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
  	    {
  	      item_name = ENCODE_SYSTEM (item_name);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
  	    }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
  	      descrip = ENCODE_SYSTEM (descrip);
! 	      ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
  	    }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1818,1848 ****
        i = 0;
        while (i < menu_items_used)
  	{
! 	  if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
  	    {
  	      subprefix_stack[submenu_depth++] = prefix;
  	      prefix = entry;
  	      i++;
  	    }
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
  	    {
  	      prefix = subprefix_stack[--submenu_depth];
  	      i++;
  	    }
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	    {
! 	      prefix
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  /* Ignore a nil in the item list.
  	     It's meaningful only for dialog boxes.  */
! 	  else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
  	    i += 1;
  	  else
  	    {
! 	      entry
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
--- 1870,1898 ----
        i = 0;
        while (i < menu_items_used)
  	{
! 	  if (EQ (AREF (menu_items, i), Qnil))
  	    {
  	      subprefix_stack[submenu_depth++] = prefix;
  	      prefix = entry;
  	      i++;
  	    }
! 	  else if (EQ (AREF (menu_items, i), Qlambda))
  	    {
  	      prefix = subprefix_stack[--submenu_depth];
  	      i++;
  	    }
! 	  else if (EQ (AREF (menu_items, i), Qt))
  	    {
! 	      prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  /* Ignore a nil in the item list.
  	     It's meaningful only for dialog boxes.  */
! 	  else if (EQ (AREF (menu_items, i), Qquote))
  	    i += 1;
  	  else
  	    {
! 	      entry	= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
***************
*** 1903,1910 ****
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
!     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
      pane_string = (NILP (pane_name)
  		   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
--- 1953,1960 ----
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
!     prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
      pane_string = (NILP (pane_name)
  		   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
***************
*** 1924,1934 ****
  	/* Create a new item within current pane.  */
  	Lisp_Object item_name, enable, descrip, help;
  
! 	item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
! 	enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
! 	descrip
! 	  = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
!         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
  	
  	if (NILP (item_name))
  	  {
--- 1974,1983 ----
  	/* Create a new item within current pane.  */
  	Lisp_Object item_name, enable, descrip, help;
  
! 	item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
! 	enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
! 	descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
!         help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
  	
  	if (NILP (item_name))
  	  {
***************
*** 1957,1963 ****
  	if (!NILP (descrip))
  	  wv->key = (char *) SDATA (descrip);
  	wv->value = (char *) SDATA (item_name);
! 	wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
  	wv->enabled = !NILP (enable);
  	wv->help = Qnil;
  	prev_wv = wv;
--- 2006,2012 ----
  	if (!NILP (descrip))
  	  wv->key = (char *) SDATA (descrip);
  	wv->value = (char *) SDATA (item_name);
! 	wv->call_data = (void *) &AREF (menu_items, i);
  	wv->enabled = !NILP (enable);
  	wv->help = Qnil;
  	prev_wv = wv;
***************
*** 2027,2042 ****
  	{
  	  Lisp_Object entry;
  
! 	  if (EQ (XVECTOR (menu_items)->contents[i], Qt))
  	    {
! 	      prefix
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  else
  	    {
! 	      entry
! 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
--- 2076,2089 ----
  	{
  	  Lisp_Object entry;
  
! 	  if (EQ (AREF (menu_items, i), Qt))
  	    {
! 	      prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  	      i += MENU_ITEMS_PANE_LENGTH;
  	    }
  	  else
  	    {
! 	      entry	= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
  	      if (menu_item_selection == i)
  		{
  		  if (keymaps != 0)
***************
*** 2117,2127 ****
  	     we can't deallocate the memory otherwise.  */
  	  if (get_menu_item_info)
  	    {
! 	      out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
  #ifdef MENU_DEBUG
! 	      DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
  #endif
- 	      strcpy (out_string, wv->name);
  	      fuFlags = MF_OWNERDRAW | MF_DISABLED;
  	    }
  	  else
--- 2164,2174 ----
  	     we can't deallocate the memory otherwise.  */
  	  if (get_menu_item_info)
  	    {
!               out_string = (char *) local_alloc (strlen (wv->name) + 1);
!               strcpy (out_string, wv->name);
  #ifdef MENU_DEBUG
! 	      DebPrint ("Menu: allocing %ld for owner-draw", out_string);
  #endif
  	      fuFlags = MF_OWNERDRAW | MF_DISABLED;
  	    }
  	  else
***************
*** 2277,2283 ****
  #ifdef MENU_DEBUG
  	  DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
! 	  LocalFree (info.dwItemData);
  	}
  
        /* Recurse down submenus.  */
--- 2324,2330 ----
  #ifdef MENU_DEBUG
  	  DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
! 	  local_free (info.dwItemData);
  	}
  
        /* Recurse down submenus.  */

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
@ 2002-08-01  7:54 jasonr
  0 siblings, 0 replies; 13+ messages in thread
From: jasonr @ 2002-08-01  7:54 UTC (permalink / raw)
  Cc: emacs-devel

Are you able to install this yourself, or can someone else
do it for you?  I am currently without an internet
connection (or phone line even) at home.

>  from:    David Ponce <david@dponce.com>
>  date:    Wed, 31 Jul 2002 23:37:05
>  to:      rms@gnu.org
>  cc:      emacs-devel@gnu.org
>  subject: Re: NT Emacs crashes when selecting a menubar item
> 
> Richard Stallman wrote:
> 
> >I figured out how Lisp code was getting called during that loop.
> >xmenu.c had the same bug, so I fixed it there.
> >
> >Now we need a Windows hacker to adapt the same fix to w32menu.c.
> >Perhaps macmenu.c needs the same change.
> >
> >Thanks for figuring this out.
> >
> >
> Hi Richard,
> 
> I adapted your changes from xmenu.c to the version of w32menu.c where
> I fixed another bug with popup menu, and generalized use of the macros
> AREF, ASET, ASIZE, to access vectors.  Attached you will find a new
> diff.  The change log is at end.
> 
> I currently use this new version and can confirm that you fixed the bug
> :-)
> 
> Thank you very much for your support!
> David
> 
> ------------ Change Log:
> 
> (local_heap, local_alloc, local_free): New macros.
> (malloc_widget_value, free_widget_value)
> (w32_free_submenu_strings): Use them.
> 
> (push_submenu_start, push_submenu_end, push_left_right_boundary)
> (push_menu_pane, push_menu_item, single_keymap_panes)
> (single_menu_item, Fx_popup_menu, menubar_selection_callback)
> (single_submenu, set_frame_menubar)
> (w32_menu_show, w32_dialog_show): Use AREF, ASET, ASIZE.
> 
> (Fx_popup_menu):  Don't show pop up menu until preceding one is
> actually cleaned up.  Moved UNGCPRO outside #ifdef HAVE_MENUS block.
> 
> Changes adapted from xmenu.c
> 
> (set_frame_menubar): First parse all submenus,
> then make widget_value trees from them.
> Don't allocate any widget_value objects
> until we are done with the parsing.
> (parse_single_submenu): New function.
> (digest_single_submenu): New function.
> (single_submenu): Function deleted, replaced by those two.
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: NT Emacs crashes when selecting a menubar item
@ 2002-08-01 11:39 David PONCE
  0 siblings, 0 replies; 13+ messages in thread
From: David PONCE @ 2002-08-01 11:39 UTC (permalink / raw)
  Cc: emacs-devel

> Are you able to install this yourself, or can someone else
> do it for you?  I am currently without an internet
> connection (or phone line even) at home.

I can't do it myself.  Richard?

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2002-08-01 11:39 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-01 11:39 NT Emacs crashes when selecting a menubar item David PONCE
  -- strict thread matches above, loose matches on Subject: below --
2002-08-01  7:54 jasonr
     [not found] <3D2A791A00A0862A@mel-rta9.wanadoo.fr>
2002-07-31 21:57 ` Richard Stallman
2002-07-31 22:37   ` David Ponce
2002-07-30 11:28 David PONCE
2002-07-24 18:55 David Ponce
2002-07-25 18:07 ` Richard Stallman
2002-07-26 12:30   ` David Ponce
2002-07-27 18:52     ` Richard Stallman
2002-07-28 16:56       ` David Ponce
2002-07-29 17:30         ` Richard Stallman
2002-07-29 18:16           ` David Ponce
2002-07-30 18:46             ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).