mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-03 18:30:49 +02:00
fix for command substitution string parsing that resulted in top-level unwind-protects being run in the wrong spot; fix for delimiter byte being part of invalid multibyte character in read builtin
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+15
-9
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -880,6 +880,9 @@
|
||||
/* 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+5
-5
@@ -770,11 +770,11 @@ PPAARRAAMMEETTEERRSS
|
||||
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 AArrrraayyss 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, _v_a_l_u_e 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, _v_a_l_u_e is expanded and appended to
|
||||
the variable's value.
|
||||
|
||||
A variable can be assigned the _n_a_m_e_r_e_f attribute using the --nn option to
|
||||
the ddeeccllaarree or llooccaall builtin commands (see the descriptions of ddeeccllaarree
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+70
-53
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user