]> git.ipfire.org Git - thirdparty/readline.git/commitdiff
fixes for readline asan issues
authorChet Ramey <chet.ramey@case.edu>
Mon, 13 Mar 2023 21:21:01 +0000 (17:21 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 13 Mar 2023 21:21:01 +0000 (17:21 -0400)
display.c
histexpand.c
histlib.h
history.c
isearch.c
kill.c
misc.c
search.c
vi_mode.c

index 1ebb2eb5f19435897bab993bb495ef2799ba80bb..ce9dacd830d03b92a7b8de7259f753808e737d81 100644 (file)
--- 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;
index 38a4953137180aec3f7af22975857b273b7fa442..25d962c2cedac0709949616a59ebe14184fe9564 100644 (file)
@@ -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;
        }
 
index ca698aca2702b95a9c9d0080197bbe31e96f35e8..7189a07c1239865dfd42e179eb0e3137ca4de06d 100644 (file)
--- 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 */
index 781f124a04b208a1b4d2bfc73c564ec54a7fdc7d..42580301c46385b29a1b2275a27a2b99b7a010eb 100644 (file)
--- 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,
index 89c933863a4ebcde69c7678acfd38a4f7bc9c5d8..c99072fdd1a855dce602dce0c77497eb88026399 100644 (file)
--- 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 659e57fd4cc6a41f6294dd5427e0091379a51a92..1dfe3c57c053c7dcd1d83f4525f6bb59070f29a1 100644 (file)
--- 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 e9bbfa260d3dc352f420eddbb6706133ae5481af..c797ff749c04b652de96e3857f24211baa74ec23 100644 (file)
--- 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;
     }
index b7be876fe26b6bd8920e583a8ea373269386346f..965722bac3d43fd558294d2ba2b90b39442c80ed 100644 (file)
--- 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);
index 96523c731dc360afa25581dfbada94a1571e8d27..e85fd101bd197c142b965712ae90e4afebabd2f1 100644 (file)
--- a/vi_mode.c
+++ b/vi_mode.c
 #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;