]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
asan fuzzing fixes; fix incomplete multibyte chars in history expansion; new nosort...
authorChet Ramey <chet.ramey@case.edu>
Mon, 1 May 2023 13:59:55 +0000 (09:59 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 1 May 2023 13:59:55 +0000 (09:59 -0400)
CWRU/CWRU.chlog
bashline.c
doc/bash.1
doc/bashref.texi
lib/readline/histexpand.c
lib/readline/misc.c
lib/readline/text.c
pathexp.c
pathexp.h

index a306fa15b27d0e8d052d711511ca414cb8c53c00..49734eb5e2853f5667ba9e49f3442534b37851e5 100644 (file)
@@ -6040,7 +6040,8 @@ builtins/complete.def
          variable in which to store the completions.
        - compgen_builtin: if the -V option is supplied, store the possible
          completions into VARNAME instead of printing them on stdout. From a
-         patch from Grisha Levit <grishalevit@gmail.com>
+         patch from Grisha Levit <grishalevit@gmail.com>, idea originally
+         from konsolebox <konsolebox@gmail.com> back in 2/2022
 
 doc/bash.1,lib/readline/doc/rluser.texi
        - compgen: document new -V option
@@ -6150,6 +6151,7 @@ lib/readline/display.c
        - _rl_move_cursor_relative: when checking to see whether data is within
          the invisible line, make sure to stay within the invisible line
          line break boundaries
+         From a report by minipython <599192367@qq.com>
 
 lib/readline/search.c
        - dispose_saved_search_line: new function, either unsave the saved
@@ -6163,3 +6165,30 @@ lib/readline/search.c
        - noninc_dosearch,rl_history_search_internal: call dispose_saved_search_line
          before calling make_history_line_current
 
+lib/readline/misc.c
+       - _rl_start_using_history: free the undo list associated with
+         _rl_saved_line_for_history, if one exists. Have to watch out for
+         this causing pointer aliasing problems, maybe add a call to
+         _hs_search_history_data()
+
+                                  4/28
+                                  ----
+pathexp.c
+       - sh_globsort: a sort specifier of `nosort' disables sorting completely
+
+doc/bash.1,doc/bashref.texi
+       - GLOBSORT: document `nosort' sort specifier
+
+bashline.c
+       - attempt_shell_completion: attempt completion with the empty command
+         for a null command word on a line with only whitespace following any
+         optional assignment statements
+       - attempt_shell_completion: make sure that the start of the command
+         word is not after rl_point before calling the programmable completion
+         for the initial word.
+         From a report by Grisha Levit <grishalevit@gmail.com>
+
+lib/readline/histexpand.c
+       - history_expand: don't read past the end of the string if it ends with
+         an incomplete multibyte character
+         From a report by Grisha Levit <grishalevit@gmail.com>
index d0d5bd487dcbd7ef6f2c4287ad6edbd03fdba8d8..6adc548e0a99a9a61f1d6ba7381326fe0ea0d210 100644 (file)
@@ -1695,10 +1695,12 @@ attempt_shell_completion (const char *text, int start, int end)
         end == index of where word to be completed ends
         if (s == start) we are doing command word completion for sure
         if (e1 == end) we are at the end of the command name and completing it */
-      if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */
+      if (start == 0 && end == 0 && e != 0 && e1 < rl_end && text[0] == '\0')  /* beginning of non-empty line */
         foundcs = 0;
       else if (start == end && start == s1 && e != 0 && e1 > end)      /* beginning of command name, leading whitespace */
        foundcs = 0;
+      else if (start == 0 && start == end && start < s1 && e != 0 && e1 > end && text[0] == '\0' && have_progcomps)    /* no command name, leading whitespace only */
+        prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs);
       else if (e == 0 && e == s && text[0] == '\0' && have_progcomps)  /* beginning of empty line */
         prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs);
       else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start]))
@@ -1742,7 +1744,14 @@ attempt_shell_completion (const char *text, int start, int end)
       /* If we have defined a compspec for the initial (command) word, call
         it and process the results like any other programmable completion. */
       if (in_command_position && have_progcomps && foundcs == 0 && iw_compspec)
-       prog_complete_matches = programmable_completions (INITIALWORD, text, s, e, &foundcs);
+       {
+         /* Do some sanity checking on S and E. Room for more here. */
+         if (s > rl_point)
+           s = rl_point;
+         if (e > rl_end)
+           e = rl_end;
+         prog_complete_matches = programmable_completions (INITIALWORD, text, s, e, &foundcs);
+       }
 
       FREE (n);
       /* XXX - if we found a COMPSPEC for the command, just return whatever
index 47753df64d3205431ae2de0fd29f877381346f38..bee814ae1855de46e20d40c427cedf24b38030bb 100644 (file)
@@ -2267,8 +2267,10 @@ and
 .IR blocks ,
 which sort the files on name, file size, modification time, access time,
 inode change time, and number of blocks, respectively.
-For example, a value of \fB\-mtime\fP sorts the results in descending
+For example, a value of \fI\-mtime\fP sorts the results in descending
 order by modification time (newest first).
+A sort specifier of \fInosort\fP disables sorting completely; the results
+are returned in the order they are read from the file system,.
 If the sort specifier is missing, it defaults to \fIname\fP,
 so a value of \fI+\fP is equivalent to the null string,
 and a value of \fI-\fP sorts by name in descending order.
index d56eb55a4a9eb8e8acef669b195f69aa8093ea57..3263a73cab93e4fff7ca6aa00f0963f9b1b70625 100644 (file)
@@ -6494,6 +6494,9 @@ inode change time, and number of blocks, respectively.
 For example, a value of @code{-mtime} sorts the results in descending
 order by modification time (newest first).
 
+A sort specifier of @samp{nosort} disables sorting completely; the results
+are returned in the order they are read from the file system,.
+
 If the sort specifier is missing, it defaults to @var{name},
 so a value of @samp{+} is equivalent to the null string,
 and a value of @samp{-} sorts by name in descending order.
index db344b497f010e7130431d10a7e6cbc33e4e489e..425ea7cf1d04fd1825e692f95e5502a21bc793fd 100644 (file)
@@ -1121,7 +1121,7 @@ history_expand (const char *hstring, char **output)
 
          c = tchar;
          memset (mb, 0, sizeof (mb));
-         for (k = 0; k < MB_LEN_MAX; k++)
+         for (k = 0; k < MB_LEN_MAX && i < l; k++)
            {
              mb[k] = (char)c;
              memset (&ps, 0, sizeof (mbstate_t));
index 6e9e03052651e91bc824c4d587167b12f1f41651..7e3efca4ec187cb801b22f2b061de9901887c88c 100644 (file)
@@ -307,6 +307,10 @@ void
 _rl_start_using_history (void)
 {
   using_history ();
+#if 1
+  if (_rl_saved_line_for_history && _rl_saved_line_for_history->data)
+    _rl_free_undo_list ((UNDO_LIST *)_rl_saved_line_for_history->data);
+#endif
   _rl_free_saved_history_line ();
   _rl_history_search_pos = -99;                /* some random invalid history position */
 }
index 356cac5f2b15ee1536679357ccf9aebeec2a1157..c7c12646e84cbd171f435eacce3c54276a696322 100644 (file)
@@ -983,6 +983,9 @@ rl_insert (int count, int c)
        break;
     }
 
+  /* If we didn't insert n and there are pending bytes, we need to insert
+     them if _rl_insert_char didn't do that on its own. */
+
   if (n != (unsigned short)-2)         /* -2 = sentinel value for having inserted N */
     {
       /* setting rl_pending_input inhibits setting rl_last_func so we do it
@@ -992,7 +995,6 @@ rl_insert (int count, int c)
       rl_executing_keyseq[rl_key_sequence_length = 0] = '\0';
       r = rl_execute_next (n);
     }
-
   return r;
 }
 
index 21eed383513a36478569dec622f5a84e833662b7..c7ca6df7a5c921df16027c14ce0103ec3557456b 100644 (file)
--- a/pathexp.c
+++ b/pathexp.c
@@ -647,15 +647,16 @@ setup_ignore_patterns (struct ignorevar *ivp)
 /* Functions to handle sorting glob results in different ways depending on
    the value of the GLOBSORT variable. */
 
-static int glob_sorttype = STAT_NONE;
+static int glob_sorttype = SORT_NONE;
 
 static STRING_INT_ALIST sorttypes[] = {
-  { "name",    STAT_NAME },
-  { "size",    STAT_SIZE },
-  { "mtime",   STAT_MTIME },
-  { "atime",   STAT_ATIME },
-  { "ctime",   STAT_CTIME },
-  { "blocks",  STAT_BLOCKS },
+  { "name",    SORT_NAME },
+  { "size",    SORT_SIZE },
+  { "mtime",   SORT_MTIME },
+  { "atime",   SORT_ATIME },
+  { "ctime",   SORT_CTIME },
+  { "blocks",  SORT_BLOCKS },
+  { "nosort",  SORT_NOSORT },
   { (char *)NULL,      -1 }
 };
 
@@ -682,7 +683,7 @@ glob_findtype (char *t)
   int type;
 
   type = find_string_in_alist (t, sorttypes, 0);
-  return (type == -1 ? STAT_NONE : type);
+  return (type == -1 ? SORT_NONE : type);
 }
 
 void
@@ -691,7 +692,7 @@ setup_globsort (const char *varname)
   char *val;
   int r, t;
 
-  glob_sorttype = STAT_NONE;
+  glob_sorttype = SORT_NONE;
   val = get_string_value (varname);
   if (val == 0 || *val == 0)
     return;
@@ -703,7 +704,7 @@ setup_globsort (const char *varname)
     val++;                     /* allow leading `+' but ignore it */
   else if (*val == '-')
     {
-      r = STAT_REVERSE;                /* leading `-' reverses sort order */
+      r = SORT_REVERSE;                /* leading `-' reverses sort order */
       val++;
     }
 
@@ -711,25 +712,25 @@ setup_globsort (const char *varname)
     {
       /* A bare `+' means the default sort by name in ascending order; a bare
          `-' means to sort by name in descending order. */
-      glob_sorttype = STAT_NAME | r;
+      glob_sorttype = SORT_NAME | r;
       return;
     }
 
   t = glob_findtype (val);
   /* any other value is equivalent to the historical behavior */
-  glob_sorttype = (t == STAT_NONE) ? t : t | r;
+  glob_sorttype = (t == SORT_NONE) ? t : t | r;
 }
 
 static int
 globsort_namecmp (char **s1, char **s2)
 {
-  return ((glob_sorttype < STAT_REVERSE) ? strvec_posixcmp (s1, s2) : strvec_posixcmp (s2, s1));
+  return ((glob_sorttype < SORT_REVERSE) ? strvec_posixcmp (s1, s2) : strvec_posixcmp (s2, s1));
 }
 
 static int
 globsort_sizecmp (struct globsort_t *g1, struct globsort_t *g2)
 {
-  return ((glob_sorttype < STAT_REVERSE) ? g1->st.size - g2->st.size : g2->st.size - g1->st.size);
+  return ((glob_sorttype < SORT_REVERSE) ? g1->st.size - g2->st.size : g2->st.size - g1->st.size);
 }
 
 static int
@@ -738,13 +739,13 @@ globsort_timecmp (struct globsort_t *g1, struct globsort_t *g2)
   int t;
   struct timespec t1, t2;
 
-  t = (glob_sorttype < STAT_REVERSE) ? glob_sorttype : glob_sorttype - STAT_REVERSE;
-  if (t == STAT_MTIME)
+  t = (glob_sorttype < SORT_REVERSE) ? glob_sorttype : glob_sorttype - SORT_REVERSE;
+  if (t == SORT_MTIME)
     {
       t1 = g1->st.mtime;
       t2 = g2->st.mtime;
     }
-  else if (t == STAT_ATIME)
+  else if (t == SORT_ATIME)
     {
       t1 = g1->st.atime;
       t2 = g2->st.atime;
@@ -755,13 +756,13 @@ globsort_timecmp (struct globsort_t *g1, struct globsort_t *g2)
       t2 = g2->st.ctime;
     }
 
-  return ((glob_sorttype < STAT_REVERSE) ? timespec_cmp (t1, t2) : timespec_cmp (t2, t1));
+  return ((glob_sorttype < SORT_REVERSE) ? timespec_cmp (t1, t2) : timespec_cmp (t2, t1));
 }
 
 static int
 globsort_blockscmp (struct globsort_t *g1, struct globsort_t *g2)
 {
-  return ((glob_sorttype < STAT_REVERSE) ? g1->st.blocks - g2->st.blocks : g2->st.blocks - g1->st.blocks);
+  return ((glob_sorttype < SORT_REVERSE) ? g1->st.blocks - g2->st.blocks : g2->st.blocks - g1->st.blocks);
 }
 
 static struct globsort_t *
@@ -803,19 +804,19 @@ globsort_sortarray (struct globsort_t *garray, size_t len)
   int t;
   QSFUNC *sortfunc;
 
-  t = (glob_sorttype < STAT_REVERSE) ? glob_sorttype : glob_sorttype - STAT_REVERSE;
+  t = (glob_sorttype < SORT_REVERSE) ? glob_sorttype : glob_sorttype - SORT_REVERSE;
 
   switch (t)
     {
-    case STAT_SIZE:
+    case SORT_SIZE:
       sortfunc = (QSFUNC *)globsort_sizecmp;
       break;
-    case STAT_ATIME:
-    case STAT_MTIME:
-    case STAT_CTIME:
+    case SORT_ATIME:
+    case SORT_MTIME:
+    case SORT_CTIME:
       sortfunc = (QSFUNC *)globsort_timecmp;
       break;
-    case STAT_BLOCKS:
+    case SORT_BLOCKS:
       sortfunc = (QSFUNC *)globsort_blockscmp;
       break;
     default:
@@ -832,9 +833,12 @@ sh_sortglob (char **results)
   size_t rlen;
   struct globsort_t *garray;
 
-  if (glob_sorttype == STAT_NONE || glob_sorttype == STAT_NAME)
+  if (glob_sorttype == SORT_NOSORT || glob_sorttype == (SORT_NOSORT|SORT_REVERSE))
+    return;
+
+  if (glob_sorttype == SORT_NONE || glob_sorttype == SORT_NAME)
     globsort_sortbyname (results);     /* posix sort */
-  else if (glob_sorttype == (STAT_NAME|STAT_REVERSE))
+  else if (glob_sorttype == (SORT_NAME|SORT_REVERSE))
     globsort_sortbyname (results);     /* posix sort reverse order */
   else
     {
index 87da5f9e9c0afd60f231ee3810acc830a1cea0c6..6f80ca086a2979706d1aa919bb871f510971171a 100644 (file)
--- a/pathexp.h
+++ b/pathexp.h
@@ -105,15 +105,16 @@ extern int should_ignore_glob_matches (void);
 extern void ignore_glob_matches (char **);
 
 /* Definitions for glob sorting */
-#define STAT_NONE      0
-#define STAT_NAME      1
-#define STAT_SIZE      2
-#define STAT_MTIME     3
-#define STAT_ATIME     4
-#define STAT_CTIME     5
-#define STAT_BLOCKS    6
-
-#define STAT_REVERSE   128
+#define SORT_NONE      0
+#define SORT_NAME      1
+#define SORT_SIZE      2
+#define SORT_MTIME     3
+#define SORT_ATIME     4
+#define SORT_CTIME     5
+#define SORT_BLOCKS    6
+#define SORT_NOSORT    7
+
+#define SORT_REVERSE   128
 
 extern void setup_globsort (const char *);