]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix for command substitution string parsing that resulted in top-level unwind-protect...
authorChet Ramey <chet.ramey@case.edu>
Sun, 4 May 2025 21:21:25 +0000 (17:21 -0400)
committerChet Ramey <chet.ramey@case.edu>
Sun, 4 May 2025 21:21:25 +0000 (17:21 -0400)
CWRU/CWRU.chlog
builtins/evalstring.c
builtins/read.def
config.h.in
configure
configure.ac
doc/bash.0
doc/bash.1
doc/bashref.texi
execute_cmd.c
lib/sh/zread.c

index a96c3dc462cbcd342588cc0ad760589b5cecd397..58c4975ab8137925b82f3ace7bab311a0a299aaa 100644 (file)
@@ -11186,3 +11186,27 @@ parse.y
          newline, among other things.
          From https://savannah.gnu.org/patch/?10517
 
+                                  4/29
+                                  ----
+builtins/evalstring.c
+       - parse_string: only run the top-level unwind-protects if we're
+         actually going to be calling jump_to_top_level(); otherwise let
+         xparse_dolparen take care of it
+         From a report by Александр Ушаков <aushakov@astralinux.ru>
+
+                                   5/1
+                                   ---
+lib/sh/zread.c
+       - zungetc: rework to use a local 16-byte buffer so we can push back
+         multiple characters whether we use read or zread
+       - zread/zreadretry/zreadintr/zreadc/zreadcintr/zreadn: changed to use
+         zpopbuf to check whether we have pushed back bytes
+       - zreset,zsyncfd: reset the pushback buffer indices
+
+builtins/read.def
+       - read_mbchar: handle the delimiter being part of an invalid multibyte
+         character, not just the byte that makes the multibyte character
+         invalid: keep track of where the delimiter char is in the buffer and
+         use zungetc to push back that character and everything we read
+         after it so subsequent buffered (zread) or unbuffered (read) reads
+         will return them
index 8a9cf2d731e148534c7f54028c91b4ecb67f90f0..d962f825a3d09be0a3b3d5f367e5f35846af70d0 100644 (file)
@@ -725,7 +725,8 @@ parse_string (char *string, const char *from_file, int flags, COMMAND **cmdp, ch
 
       if (current_token == yacc_EOF || current_token == shell_eof_token)
        {
-         if (current_token == shell_eof_token)
+         /* check for EOFTOKEN out of paranoia */
+         if ((parser_state & PST_EOFTOKEN) && (current_token == shell_eof_token))
            rewind_input_string ();
          break;
        }
@@ -744,10 +745,10 @@ out:
      us, after doing cleanup */
   if (should_jump_to_top_level)
     {
-      if (parse_and_execute_level == 0)
-       top_level_cleanup ();
       if (code == DISCARD)
        return -DISCARD;
+      if (parse_and_execute_level == 0)
+       top_level_cleanup ();
       jump_to_top_level (code);
     }
 
index 98bb0470c20cddf1957c51977270675ff3ed86a0..3b13385fa306d1940b8ca14015b776f37c64c074 100644 (file)
@@ -1159,7 +1159,7 @@ static int
 read_mbchar (int fd, char *string, int ind, int ch, int delim, int unbuffered)
 {
   char mbchar[MB_LEN_MAX + 1];
-  int i, n, r;
+  int i, n, r, delim_ind;
   char c;
   size_t ret;
   mbstate_t ps, ps_back;
@@ -1167,7 +1167,8 @@ read_mbchar (int fd, char *string, int ind, int ch, int delim, int unbuffered)
 
   memset (&ps, '\0', sizeof (mbstate_t));
   memset (&ps_back, '\0', sizeof (mbstate_t));
-  
+
+  delim_ind = 0;
   mbchar[0] = ch;
   i = 1;
   for (n = 0; n <= MB_LEN_MAX; n++)
@@ -1187,19 +1188,24 @@ read_mbchar (int fd, char *string, int ind, int ch, int delim, int unbuffered)
            r = zreadc (fd, &c);
          if (r <= 0)
            goto mbchar_return;
+         if ((unsigned char)c == delim)
+           delim_ind = i;
          mbchar[i++] = c;      
          continue;
        }
       else if (ret == (size_t)-1)
        {
-         /* If we read (i > 1) a delimiter character (c == delimiter)
-            that makes this an invalid multibyte character, we can't just
-            add it to the input string and treat it as a byte.
-            We need to push it back so a subsequent zread will pick it up. */
-         if (i > 1 && (unsigned char)c == delim)
+         /* If we read (i > 1) a delimiter character (delim_ind >= 1)
+            that is a part of this invalid multibyte character, we can't
+            just add it to the input string and treat it as a byte.
+            We need to push it and everything we read after it back so a
+            subsequent zread will pick it up. */
+         if (i > 1 && delim_ind >= 1)
            {
-             zungetc ((unsigned char)c);
-             i--;
+             size_t j;
+             for (j = delim_ind; j < i; j++)
+               zungetc ((unsigned char)mbchar[j]);
+             i = delim_ind;
            }
          break;                /* invalid multibyte character */
        }
index 7dac61a971bbcad41125fe33eff511a954c80b8d..1367eaaa799f5d3c4e14562357a7b06efc69950c 100644 (file)
 /* Define if you have the snprintf function.  */
 #undef HAVE_SNPRINTF
 
+/* Define if you have the statfs function.  */
+#undef HAVE_STATFS
+
 /* Define if you have the strcasecmp function.  */
 #undef HAVE_STRCASECMP
 
index 0ef72d7668c2cbb9d45809c1a0acdc2ba0f2e12f..b7da824da9e1e759eb6641d2ad7dd2a617837b2c 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac for Bash 5.3, version 5.077.
+# From configure.ac for Bash 5.3, version 5.078.
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.72 for bash 5.3-rc1.
 #
@@ -15581,6 +15581,12 @@ if test "x$ac_cv_func_setitimer" = xyes
 then :
   printf "%s\n" "#define HAVE_SETITIMER 1" >>confdefs.h
 
+fi
+ac_fn_c_check_func "$LINENO" "statfs" "ac_cv_func_statfs"
+if test "x$ac_cv_func_statfs" = xyes
+then :
+  printf "%s\n" "#define HAVE_STATFS 1" >>confdefs.h
+
 fi
 ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp"
 if test "x$ac_cv_func_tcgetpgrp" = xyes
index a9e8ce935f850a7f7c382a8a75c1625993499ab2..fdf542fa49b5cd60df7e2e4e0e31d5e44bb5c190 100644 (file)
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-AC_REVISION([for Bash 5.3, version 5.077])dnl
+AC_REVISION([for Bash 5.3, version 5.078])dnl
 
 define(bashvers, 5.3)
 define(relstatus, rc1)
@@ -874,7 +874,8 @@ AC_CHECK_FUNCS(dup2 eaccess fcntl getdtablesize getentropy getgroups \
                gethostname getpagesize getpeername getrandom getrlimit \
                getrusage gettimeofday kill killpg lstat nanosleep \
                pselect readlink \
-               select setdtablesize setitimer tcgetpgrp uname ulimit waitpid)
+               select setdtablesize setitimer statfs \
+               tcgetpgrp uname ulimit waitpid)
 AC_REPLACE_FUNCS(rename)
 
 dnl checks for c library functions
index 9d95e20bcdf0ae7f998d70a7c5218c9c1779131d..e01a1afee7b8841585548103d018b4b7b03f586a 100644 (file)
@@ -770,11 +770,11 @@ P\bPA\bAR\bRA\bAM\bME\bET\bTE\bER\bRS\bS
        value.  The current value is usually an integer constant, but may be an
        expression.  When "+=" is applied to an array variable  using  compound
        assignment (see A\bAr\brr\bra\bay\bys\bs below), the variable's value is not unset (as it
-       is when using and new values are appended to the array beginning at one
-       greater than the array's maximum index (for indexed arrays) or added as
-       additional  key-value pairs in an associative array.  When applied to a
-       string-valued variable, _\bv_\ba_\bl_\bu_\be is expanded and  appended  to  the  vari-
-       able's value.
+       is  when using "="), and new values are appended to the array beginning
+       at one greater than the array's maximum index (for indexed  arrays)  or
+       added  as additional key-value pairs in an associative array.  When ap-
+       plied to a string-valued variable, _\bv_\ba_\bl_\bu_\be is expanded  and  appended  to
+       the variable's value.
 
        A variable can be assigned the _\bn_\ba_\bm_\be_\br_\be_\bf attribute using the -\b-n\bn option to
        the  d\bde\bec\bcl\bla\bar\bre\be or l\blo\boc\bca\bal\bl builtin commands (see the descriptions of d\bde\bec\bcl\bla\bar\bre\be
index b03c9906ceaa79a7dabea72cb4de6c8c9a0f7e82..5af3492f7dc6ac17535d526436fa2ab2780556c6 100644 (file)
@@ -1449,7 +1449,7 @@ is applied to an array variable using compound assignment
 below),
 the variable's value is not unset
 (as it is when using
-.@ = ),
+.Q = ),
 and new values are appended to the array
 beginning at one greater than the array's maximum index (for indexed arrays)
 or added as additional key\-value pairs in an associative array.
index dd3f4a306e82dcd08eebf0e33848c0026aa29279..06c45564d4bf6bc8b3faddfdfc44945289f12d29 100644 (file)
@@ -9836,6 +9836,12 @@ the arguments as key sequences to bind.
 Interactive shells will notify the user of completed jobs while sourcing a
 script.
 Newer versions defer notification until script execution completes.
+@ignore
+@item
+Bash will not try to execute a shell function whose name contains a slash.
+Previous versions disallowed this in @sc{posix} mode but allowed it by
+default.
+@end ignore
 @end itemize
 
 @end table
index 7387e7303ca348af2097881f20cf30f47a934654..7f0b61cf08907124cd7ad66238202fa65d2999f3 100644 (file)
@@ -4669,7 +4669,11 @@ execute_simple_command (SIMPLE_COM *simple_command, int pipe_in, int pipe_out, i
            builtin_is_special = 1;
        }
       if (builtin == 0)
+#if 0  /*TAG bash-5.4 rob@landley.net 5/1/2025 */
+       func = ((shell_compatibility_level <= 52 && posixly_correct == 0) || absolute_program (words->word->word) == 0) ? find_function (words->word->word) : 0;
+#else
        func = (posixly_correct == 0 || absolute_program (words->word->word) == 0) ? find_function (words->word->word) : 0;
+#endif
     }
 
   /* What happens in posix mode when an assignment preceding a command name
index a3e12abd122f3ff6d608861140032cf4a4eaf684..9246d1e2033507ca122b3fd290e6960858468931 100644 (file)
@@ -57,8 +57,41 @@ void zreset (void);
 
 int zungetc (int);
 
-/* Provide one character of pushback whether we are using read or zread. */
-static int zpushedchar = -1;
+/* Provide 16 bytes of pushback whether we are using read or zread. Only used
+   by the read builtin when reading invalid multibyte characters. */
+#define ZPUSHSIZE 16
+
+static size_t zpushind, zpopind;
+static unsigned char zpushbuf[ZPUSHSIZE];
+static unsigned char zbufchar;
+
+static inline int
+zbufpop(unsigned char *cp)
+{
+  if (zpushind == zpopind)
+    return (0);
+  *cp = zpushbuf[zpopind++];
+  if (zpopind == zpushind)
+    zpopind = zpushind = 0;    /* reset, buffer empty */
+  return 1;
+}
+
+static inline int
+zbufpush(int c)
+{
+  if (zpushind == ZPUSHSIZE - 1)
+    return 0;
+  zpushbuf[zpushind++] = c;
+  return 1;
+}
+
+/* Add C to the pushback buffer. Can't push back EOF */
+int
+zungetc (int c)
+{
+  zbufpush (c);
+  return c;
+}
 
 /* Read LEN bytes from FD into BUF.  Retry the read on EINTR.  Any other
    error causes the loop to break. */
@@ -69,11 +102,10 @@ zread (int fd, char *buf, size_t len)
 
   check_signals ();    /* check for signals before a blocking read */
 
-  /* If we pushed a char back, return it immediately */
-  if (zpushedchar != -1)
+  /* If we pushed chars back, return the oldest one immediately */
+  if (zbufpop (&zbufchar))
     {
-      *buf = (unsigned char)zpushedchar;
-      zpushedchar = -1;
+      *buf = zbufchar;
       return 1;
     }
 
@@ -114,11 +146,10 @@ zreadretry (int fd, char *buf, size_t len)
   ssize_t r;
   int nintr;
 
-  /* If we pushed a char back, return it immediately */
-  if (zpushedchar != -1)
+  /* If we pushed chars back, return the oldest one immediately */
+  if (zbufpop (&zbufchar))
     {
-      *buf = (unsigned char)zpushedchar;
-      zpushedchar = -1;
+      *buf = zbufchar;
       return 1;
     }
 
@@ -143,14 +174,13 @@ zreadintr (int fd, char *buf, size_t len)
 {
   check_signals ();
 
-  /* If we pushed a char back, return it immediately */
-  if (zpushedchar != -1)
-    {
-      *buf = (unsigned char)zpushedchar;
-      zpushedchar = -1;
-      return 1;
-    }
-
+  /* If we pushed chars back, return the oldest one immediately */
+  if (zbufpop (&zbufchar))  
+    {    
+      *buf = zbufchar;        
+      return 1;              
+    }                            
+        
   return (read (fd, buf, len));
 }
 
@@ -166,14 +196,13 @@ zreadc (int fd, char *cp)
 {
   ssize_t nr;
 
-  /* If we pushed a char back, return it immediately */
-  if (zpushedchar != -1 && cp)
-    {
-      *cp = (unsigned char)zpushedchar;
-      zpushedchar = -1;
-      return 1;
-    }
-
+  /* If we pushed chars back, return the oldest one immediately */
+  if (cp && zbufpop (&zbufchar))  
+    {    
+      *cp = zbufchar;        
+      return 1;              
+    }                            
+        
   if (lind == lused || lused == 0)
     {
       nr = zread (fd, lbuf, sizeof (lbuf));
@@ -197,12 +226,11 @@ zreadcintr (int fd, char *cp)
 {
   ssize_t nr;
 
-  /* If we pushed a char back, return it immediately */
-  if (zpushedchar != -1 && cp)
-    {
-      *cp = (unsigned char)zpushedchar;
-      zpushedchar = -1;
-      return 1;
+  /* If we pushed chars back, return the oldest one immediately */
+  if (cp && zbufpop (&zbufchar))  
+    {    
+      *cp = zbufchar;        
+      return 1;              
     }
 
   if (lind == lused || lused == 0)
@@ -228,11 +256,11 @@ zreadn (int fd, char *cp, size_t len)
 {
   ssize_t nr;
 
-  if (zpushedchar != -1 && cp)
-    {
-      *cp = zpushedchar;
-      zpushedchar = -1;
-      return 1;
+  /* If we pushed chars back, return the oldest one immediately */
+  if (cp && zbufpop (&zbufchar))  
+    {    
+      *cp = zbufchar;        
+      return 1;              
     }
 
   if (lind == lused || lused == 0)
@@ -253,25 +281,11 @@ zreadn (int fd, char *cp, size_t len)
   return 1;
 }
 
-int
-zungetc (int c)
-{
-  if (zpushedchar == -1)
-    {
-      zpushedchar = c;
-      return c;
-    }
-
-  if (c == EOF || lind == 0)
-    return (EOF);
-  lbuf[--lind] = c;            /* XXX */
-  return c;
-}
-
 void
 zreset (void)
 {
   lind = lused = 0;
+  zpushind = zpopind = 0;
 }
 
 /* Sync the seek pointer for FD so that the kernel's idea of the last char
@@ -287,5 +301,8 @@ zsyncfd (int fd)
     r = lseek (fd, -off, SEEK_CUR);
 
   if (r != -1)
-    lused = lind = 0;
+    {
+      lused = lind = 0;
+      zpushind = zpopind = 0;
+    }
 }