From 48621e69064ea74eef6530d299cdc3548e170ce2 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 11 Oct 2013 14:01:48 +0300 Subject: [PATCH] Fix bug #15575 with crashes in TTY menus. src/xdisp.c (display_tty_menu_item): Make sure we never write beyond the end of the frame's glyph matrix. src/term.c (tty_menu_display): Don't move cursor while overwriting frame's glyphs with menu items. Limit the number of items displayed to what can be shown on the available screen lines, excluding the echo area. (tty_menu_activate): Limit the Y coordinate allowed by read_menu_input to the last screen line used for menu display. --- src/ChangeLog | 12 ++++++++++++ src/term.c | 10 +++++++--- src/xdisp.c | 9 +++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index df44bca7b1c..6947c5eddd5 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +2013-10-11 Eli Zaretskii + + * xdisp.c (display_tty_menu_item): Make sure we never write beyond + the end of the frame's glyph matrix. (Bug#15575) + + * term.c (tty_menu_display): Don't move cursor while overwriting + frame's glyphs with menu items. Limit the number of items + displayed to what can be shown on the available screen lines, + excluding the echo area. + (tty_menu_activate): Limit the Y coordinate allowed by + read_menu_input to the last screen line used for menu display. + 2013-10-11 Paul Eggert * lisp.h (eassume): New macro. diff --git a/src/term.c b/src/term.c index a4f8f2ea17c..9437faee8a2 100644 --- a/src/term.c +++ b/src/term.c @@ -2919,17 +2919,20 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces, int i, face, width, enabled, mousehere, row, col; struct frame *sf = SELECTED_FRAME (); struct tty_display_info *tty = FRAME_TTY (sf); + /* Don't try to display more menu items than the console can display + using the available screen lines. Exclude the echo area line, as + it will be overwritten by the help-echo anyway. */ + int max_items = min (menu->count, FRAME_LINES (sf) - 1); menu_help_message = NULL; width = menu->width; col = cursorX (tty); row = cursorY (tty); - for (i = 0; i < menu->count; i++) + for (i = 0; i < max_items; i++) { int max_width = width + 2; /* +2 for padding blanks on each side */ - cursor_to (sf, y + i, x); if (menu->submenu[i]) max_width += 2; /* for displaying " >" after the item */ enabled @@ -3285,7 +3288,8 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, while (!leave) { int input_status; - int min_y = state[0].y, max_y = min_y + state[0].menu->count - 1; + int min_y = state[0].y; + int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf)) - 1; input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time); if (input_status) diff --git a/src/xdisp.c b/src/xdisp.c index 6c189c698e1..7cfb0ab51ad 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20640,6 +20640,14 @@ display_tty_menu_item (const char *item_text, int width, int face_id, eassert (FRAME_TERMCAP_P (f)); + /* Don't write beyond the matrix's last row. This can happen for + TTY screens that are not high enough to show the entire menu. + (This is actually a bit of defensive programming, as + tty_menu_display already limits the number of menu items to one + less than the number of screen lines.) */ + if (y >= f->desired_matrix->nrows) + return; + init_iterator (&it, w, -1, -1, f->desired_matrix->rows + y, MENU_FACE_ID); it.first_visible_x = 0; it.last_visible_x = FRAME_COLS (f) - 1; @@ -20654,6 +20662,7 @@ display_tty_menu_item (const char *item_text, int width, int face_id, /* Arrange for the menu item glyphs to start at (X,Y) and have the desired face. */ + eassert (x < f->desired_matrix->matrix_w); it.current_x = it.hpos = x; it.current_y = it.vpos = y; saved_used = row->used[TEXT_AREA]; -- 2.39.5