From: Chet Ramey Date: Mon, 13 Mar 2023 21:21:01 +0000 (-0400) Subject: fixes for readline asan issues X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e4a66763cb4fc62fb1c09835c0290242966c7391;p=thirdparty%2Freadline.git fixes for readline asan issues --- diff --git a/display.c b/display.c index 1ebb2eb..ce9dacd 100644 --- a/display.c +++ b/display.c @@ -620,7 +620,11 @@ rl_expand_prompt (char *prompt) local_prompt_invis_chars[0] = 0; if (prompt == 0 || *prompt == 0) - return (0); + { + local_prompt = xmalloc (sizeof (char)); + local_prompt[0] = '\0'; + return (0); + } p = strrchr (prompt, '\n'); if (p == 0) @@ -1093,6 +1097,8 @@ rl_redisplay (void) wc_width = (temp >= 0) ? temp : 1; } } + else + wc_width = 1; /* make sure it's set for the META_CHAR check */ #endif if (in == rl_point) @@ -1102,12 +1108,22 @@ rl_redisplay (void) } #if defined (HANDLE_MULTIBYTE) - if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */ + if (META_CHAR (c) && wc_bytes == 1 && wc_width == 1) #else if (META_CHAR (c)) #endif { +#if 0 + /* TAG: readline-8.3 20230227 */ + /* https://savannah.gnu.org/support/index.php?110830 + asking for non-printing meta characters to be printed using an + escape sequence. */ + + /* isprint(c) handles bytes up to UCHAR_MAX */ + if (_rl_output_meta_chars == 0 || isprint (c) == 0) +#else if (_rl_output_meta_chars == 0) +#endif { char obuf[5]; int olen; diff --git a/histexpand.c b/histexpand.c index 38a4953..25d962c 100644 --- a/histexpand.c +++ b/histexpand.c @@ -984,6 +984,8 @@ history_expand (const char *hstring, char **output) squote = 0; if (string[i]) i++; + if (i >= l) + i = l; } for ( ; string[i]; i++) @@ -1054,6 +1056,11 @@ history_expand (const char *hstring, char **output) flag = (i > 0 && string[i - 1] == '$'); i++; hist_string_extract_single_quoted (string, &i, flag); + if (i >= l) + { + i = l; + break; + } } else if (history_quotes_inhibit_expansion && string[i] == '\\') { @@ -1064,7 +1071,7 @@ history_expand (const char *hstring, char **output) } } - + if (string[i] != history_expansion_char) { xfree (result); @@ -1563,6 +1570,8 @@ get_word: (delimiter != '"' || member (string[i], slashify_in_quotes))) { i++; + if (string[i] == 0) + break; continue; } diff --git a/histlib.h b/histlib.h index ca698ac..7189a07 100644 --- a/histlib.h +++ b/histlib.h @@ -1,6 +1,6 @@ /* histlib.h -- internal definitions for the history library. */ -/* Copyright (C) 1989-2009,2021-2022 Free Software Foundation, Inc. +/* Copyright (C) 1989-2009,2021-2023 Free Software Foundation, Inc. This file contains the GNU History Library (History), a set of routines for managing the text of previously typed lines. @@ -91,6 +91,7 @@ extern int _hs_history_search (const char *, int, int); /* history.c */ extern void _hs_replace_history_data (int, histdata_t *, histdata_t *); +extern int _hs_search_history_data (histdata_t *); extern int _hs_at_end_of_history (void); /* histfile.c */ diff --git a/history.c b/history.c index 781f124..4258030 100644 --- a/history.c +++ b/history.c @@ -1,6 +1,6 @@ /* history.c -- standalone history library */ -/* Copyright (C) 1989-2021 Free Software Foundation, Inc. +/* Copyright (C) 1989-2023 Free Software Foundation, Inc. This file contains the GNU History Library (History), a set of routines for managing the text of previously typed lines. @@ -458,7 +458,7 @@ _hs_replace_history_data (int which, histdata_t *old, histdata_t *new) } last = -1; - for (i = 0; i < history_length; i++) + for (i = history_length - 1; i >= 0; i--) { entry = the_history[i]; if (entry == 0) @@ -475,7 +475,27 @@ _hs_replace_history_data (int which, histdata_t *old, histdata_t *new) entry = the_history[last]; entry->data = new; /* XXX - we don't check entry->old */ } -} +} + +int +_hs_search_history_data (histdata_t *needle) +{ + register int i; + HIST_ENTRY *entry; + + if (history_length == 0 || the_history == 0) + return -1; + + for (i = history_length - 1; i >= 0; i--) + { + entry = the_history[i]; + if (entry == 0) + continue; + if (entry->data == needle) + return i; + } + return -1; +} /* Remove history element WHICH from the history. The removed element is returned to you so you can free the line, data, diff --git a/isearch.c b/isearch.c index 89c9338..c99072f 100644 --- a/isearch.c +++ b/isearch.c @@ -783,7 +783,7 @@ opcode_dispatch: else cxt->sline_index += cxt->direction; - if (cxt->sline_index < 0) + if (cxt->sline_index < 0 || cxt->sline_index > cxt->sline_len) { cxt->sline_index = 0; break; @@ -816,8 +816,8 @@ opcode_dispatch: if (cxt->sflags & SF_FAILED) { - /* XXX - reset sline_index if < 0 */ - if (cxt->sline_index < 0) + /* XXX - reset sline_index if < 0 or longer than the history line */ + if (cxt->sline_index < 0 || cxt->sline_index > cxt->sline_len) cxt->sline_index = 0; break; } diff --git a/kill.c b/kill.c index 659e57f..1dfe3c5 100644 --- a/kill.c +++ b/kill.c @@ -348,15 +348,15 @@ rl_unix_filename_rubout (int count, int key) if (count <= 0) count = 1; - while (count--) + while (rl_point > 0 && count--) { c = rl_line_buffer[rl_point - 1]; /* First move backwards through whitespace */ while (rl_point && whitespace (c)) { - rl_point--; - c = rl_line_buffer[rl_point - 1]; + if (--rl_point) + c = rl_line_buffer[rl_point - 1]; } /* Consume one or more slashes. */ @@ -377,14 +377,14 @@ rl_unix_filename_rubout (int count, int key) while (rl_point && (whitespace (c) || c == '/')) { - rl_point--; - c = rl_line_buffer[rl_point - 1]; + if (--rl_point) + c = rl_line_buffer[rl_point - 1]; } while (rl_point && (whitespace (c) == 0) && c != '/') { - rl_point--; /* XXX - multibyte? */ - c = rl_line_buffer[rl_point - 1]; + if (--rl_point) /* XXX - multibyte? */ + c = rl_line_buffer[rl_point - 1]; } } diff --git a/misc.c b/misc.c index e9bbfa2..c797ff7 100644 --- a/misc.c +++ b/misc.c @@ -340,6 +340,9 @@ rl_maybe_replace_line (void) xfree (temp->line); FREE (temp->timestamp); xfree (temp); + /* XXX - what about _rl_saved_line_for_history? if the saved undo list + is rl_undo_list, and we just put that into a history entry, should + we set the saved undo list to NULL? */ } return 0; } @@ -385,14 +388,16 @@ _rl_free_saved_history_line (void) { if (_rl_saved_line_for_history) { - if (rl_undo_list && rl_undo_list == (UNDO_LIST *)_rl_saved_line_for_history->data) - rl_undo_list = 0; - /* Have to free this separately because _rl_free_history entry can't: - it doesn't know whether or not this has application data. Only the - callers that know this is _rl_saved_line_for_history can know that - it's an undo list. */ - if (_rl_saved_line_for_history->data) - _rl_free_undo_list ((UNDO_LIST *)_rl_saved_line_for_history->data); + UNDO_LIST *sentinel; + + sentinel = (UNDO_LIST *)_rl_saved_line_for_history->data; + + /* We should only free `data' if it's not the current rl_undo_list and + it's not the `data' member in a history entry somewhere. We have to + free it separately because only the callers know it's an undo list. */ + if (sentinel && sentinel != rl_undo_list && _hs_search_history_data ((histdata_t *)sentinel) < 0) + _rl_free_undo_list (sentinel); + _rl_free_history_entry (_rl_saved_line_for_history); _rl_saved_line_for_history = (HIST_ENTRY *)NULL; } diff --git a/search.c b/search.c index b7be876..965722b 100644 --- a/search.c +++ b/search.c @@ -88,8 +88,10 @@ make_history_line_current (HIST_ENTRY *entry) xlist = _rl_saved_line_for_history ? (UNDO_LIST *)_rl_saved_line_for_history->data : 0; /* At this point, rl_undo_list points to a private search string list. */ - if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data && rl_undo_list != xlist) + if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data && rl_undo_list != xlist && + _hs_search_history_data ((histdata_t *)rl_undo_list) < 0) rl_free_undo_list (); + rl_undo_list = 0; /* XXX */ /* Now we create a new undo list with a single insert for this text. WE DON'T CHANGE THE ORIGINAL HISTORY ENTRY UNDO LIST */ @@ -621,7 +623,7 @@ rl_history_search_reinit (int flags) if (rl_point) { /* Allocate enough space for anchored and non-anchored searches */ - if (_rl_history_search_len >= history_string_size - 2) + if (_rl_history_search_len + 2 >= history_string_size) { history_string_size = _rl_history_search_len + 2; history_search_string = (char *)xrealloc (history_search_string, history_string_size); diff --git a/vi_mode.c b/vi_mode.c index 96523c7..e85fd10 100644 --- a/vi_mode.c +++ b/vi_mode.c @@ -76,6 +76,10 @@ #define INCREMENT_POS(start) (start)++ #endif /* !HANDLE_MULTIBYTE */ +/* Flags for the motion context */ +#define MOVE_SUCCESS 0 +#define MOVE_FAILED 0x01 + /* This is global so other parts of the code can check whether the last command was a text modification command. */ int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ @@ -1152,7 +1156,7 @@ _rl_mvcxt_dispose (_rl_vimotion_cxt *m) static int rl_domove_motion_callback (_rl_vimotion_cxt *m) { - int c; + int c, r, opoint; _rl_vi_last_motion = c = m->motion; @@ -1162,8 +1166,15 @@ rl_domove_motion_callback (_rl_vimotion_cxt *m) rl_extend_line_buffer (rl_end + 1); rl_line_buffer[rl_end++] = ' '; rl_line_buffer[rl_end] = '\0'; + opoint = rl_point; + + r = _rl_dispatch (c, _rl_keymap); - _rl_dispatch (c, _rl_keymap); + /* Note in the context that the motion command failed. Right now we only do + this for unsuccessful searches (ones where _rl_dispatch returns non-zero + and point doesn't move). */ + if (r != 0 && rl_point == opoint && (c == 'f' || c == 'F')) + m->flags |= MOVE_FAILED; #if defined (READLINE_CALLBACKS) if (RL_ISSTATE (RL_STATE_CALLBACK)) @@ -1198,7 +1209,7 @@ _rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m) { /* 'c' and 'C' enter insert mode after the delete even if the motion didn't delete anything, as long as the motion command is valid. */ - if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c)) + if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c) && (m->flags & MOVE_FAILED) == 0) return (vidomove_dispatch (m)); RL_UNSETSTATE (RL_STATE_VIMOTION); return (-1); @@ -1379,7 +1390,11 @@ rl_vi_delete_to (int count, int key) _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key); } else if (_rl_vimvcxt) - _rl_mvcxt_init (_rl_vimvcxt, VIM_DELETE, key); + { + /* are we being called recursively or by `y' or `c'? */ + savecxt = _rl_vimvcxt; + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key); + } else _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key); @@ -1478,7 +1493,11 @@ rl_vi_change_to (int count, int key) _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key); } else if (_rl_vimvcxt) - _rl_mvcxt_init (_rl_vimvcxt, VIM_CHANGE, key); + { + /* are we being called recursively or by `y' or `d'? */ + savecxt = _rl_vimvcxt; + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key); + } else _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key); _rl_vimvcxt->start = rl_point; @@ -1557,7 +1576,11 @@ rl_vi_yank_to (int count, int key) _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key); } else if (_rl_vimvcxt) - _rl_mvcxt_init (_rl_vimvcxt, VIM_YANK, key); + { + /* are we being called recursively or by `c' or `d'? */ + savecxt = _rl_vimvcxt; + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key); + } else _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key); _rl_vimvcxt->start = rl_point;