and though bugs are the bane of my existence, rest assured the wretched thing will get the best of care here

...
 
Commits (2)
......@@ -9462,3 +9462,77 @@ execute_cmd.c
exits unconditionally.
- execute_simple_command: make sure posix mode sets $? to non-zero
if a variable assignment error occurs preceding a non-special builtin
subst.c
- do_assignment_statements: take the code from expand_word_list_internal
that performs assignment statements, either standalone or preceding
simple command names, and factor it out into this function
- expand_word_list_internal: call do_assignment_statements where
appropriate
2/2
---
lib/glob/glob.c
- dequote_pathname: fix function definition for non-multibyte systems.
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
Makefile.in,doc/Makefile.in
- for certain targets, remove files before creating them to deal with
symlinked build trees.
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
examples/loadables/accept.c
- include limits.h before typemax.h
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
builtins/gen-helpfiles.c
- if USING_BASH_MALLOC is defined, make sure to undefine malloc as well
as free. Fixes bug reported by George R Goffe <grgoffe@yahoo.com>
builtins/Makefile.in
- install-help: now depends on $(HELPFILES_TARGET) so we make sure the
separate helpfiles are created before we try to install them if we
don't go through the `all' makefile target
configure.ac
- HELPDIR: now ${datadir}/bash/helpfiles
2/3
---
parse.y
- parse_string_to_word_list: before expanding a compound assignment
statement body, make sure to save any alias that's currently being
expanded. Restore the alias after the compound assignment is parsed.
Reported back in 11/2020 by Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com>
2/4
---
lib/readline/histexpand.c
- history_expand_internal: when calling the history_inhibit_expansion
function, make sure to call it using the string as we've expanded it
to that point (RESULT), adding the expansion and next characters
temporarily, since we make expansion decisions based on what we've
accumulated, not what we started with. This makes things like
echo abc!$!$ work, where before the second `!' inhibited expansion
because bash_history_inhibit_expansion mistakenly took it as the
second character in a `$!' word expansion. Fixes bug reported back
in 10/2020 by Paul Fox <paul.d.fox@gmail.com>
array.h
- array_pop: instead of calling array_dispose_element from this macro,
just call array_shift with the AS_DISPOSE flag
2/5
---
bashhist.c
- shell_comment: move condition to return 0 if the delimiter stack is
not empty or the shell is parsing a here document into the function
itself, don't have the callers check so the check is in one place.
Fixes bug reported by Oguz <oguzismailuysal@gmail.com>
array.h,variables.c
- ARRAY_ELEMENT_REPLACE: convenience define for modifying an array
element's value
variables.c
- pop_args: a couple of code simplifications
......@@ -649,6 +649,7 @@ ${GRAM_H}: y.tab.h
y.tab.c: parse.y
# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi
$(YACC) -d $(srcdir)/parse.y
$(RM) parser-built
touch parser-built
# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; else cp -p y.tab.h ${GRAM_H}; fi
......
......@@ -106,11 +106,14 @@ extern ARRAY *array_from_string PARAMS((char *, char *));
#define set_element_value(ae, val) ((ae)->value = (val))
#define set_max_index(a, i) ((a)->max_index = (i))
#define set_num_elements(a, n) ((a)->num_elements = (n))
/* Convenience */
#define array_push(a,v) \
do { array_rshift ((a), 1, (v)); } while (0)
#define array_pop(a) \
do { array_dispose_element (array_shift ((a), 1, 0)); } while (0)
do { array_shift ((a), 1, AS_DISPOSE); } while (0)
#define GET_ARRAY_FROM_VAR(n, v, a) \
do { \
......@@ -118,6 +121,12 @@ extern ARRAY *array_from_string PARAMS((char *, char *));
(a) = ((v) && array_p ((v))) ? array_cell (v) : (ARRAY *)0; \
} while (0)
#define ARRAY_ELEMENT_REPLACE(ae, v) \
do { \
free ((ae)->value); \
(ae)->value = (v); \
} while (0)
#define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*')
/* In eval.c, but uses ARRAY * */
......
......@@ -653,6 +653,8 @@ shell_comment (line)
char *p;
int n;
if (dstack.delimiter_depth != 0 || (parser_state & PST_HEREDOC))
return 0;
if (line == 0)
return 0;
for (p = line; p && *p && whitespace (*p); p++)
......@@ -757,7 +759,7 @@ maybe_add_history (line)
int is_comment;
hist_last_line_added = 0;
is_comment = (parser_state & PST_HEREDOC) ? 0 : shell_comment (line);
is_comment = shell_comment (line);
/* Don't use the value of history_control to affect the second
and subsequent lines of a multi-line command (old code did
......@@ -874,7 +876,7 @@ bash_add_history (line)
add_it = 1;
if (command_oriented_history && current_command_line_count > 1)
{
is_comment = (parser_state & PST_HEREDOC) ? 0 : shell_comment (line);
is_comment = shell_comment (line);
/* The second and subsequent lines of a here document have the trailing
newline preserved. We don't want to add extra newlines here, but we
......
......@@ -203,7 +203,7 @@ builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
helpdoc: gen-helpfiles
./gen-helpfiles ${HELPDIRDEFINE}
install-help:
install-help: $(HELPFILES_TARGET)
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \
test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\
( for f in helpfiles/*; do \
......
......@@ -64,6 +64,7 @@
#undef xrealloc
#undef xfree
#undef malloc
#undef free /* defined in xmalloc.h */
#endif
......
#! /bin/sh
# From configure.ac for Bash 5.1, version 5.022.
# From configure.ac for Bash 5.1, version 5.023.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for bash 5.1-maint.
#
......@@ -3400,7 +3400,7 @@ fi
HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET=
if test "$opt_separate_help" != no; then
if test "$opt_separate_help" = "yes" ; then
HELPDIR='${datadir}/bash'
HELPDIR='${datadir}/bash/helpfiles'
else
HELPDIR=$opt_separate_help
fi
......
......@@ -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.1, version 5.022])dnl
AC_REVISION([for Bash 5.1, version 5.023])dnl
define(bashvers, 5.1)
define(relstatus, maint)
......@@ -368,7 +368,7 @@ fi
HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET=
if test "$opt_separate_help" != no; then
if test "$opt_separate_help" = "yes" ; then
HELPDIR='${datadir}/bash'
HELPDIR='${datadir}/bash/helpfiles'
else
HELPDIR=$opt_separate_help
fi
......
......@@ -173,23 +173,26 @@ html: ${HTMLFILES}
pdf: ${PDFFILES}
bashref.dvi: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; }
bashref.info: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
$(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi
# experimental
bashref.pdf: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
${SET_TEXINPUTS} $(TEXI2PDF) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; }
# can also use:
# $(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bashref.texi
bashref.html: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(MAKEINFO) --html --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi
bash.info: bashref.info
${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@ ; \
$(RM) $@
${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@
bash.txt: bash.1
bash.ps: bash.1
......
......@@ -596,7 +596,8 @@ See
for a description of a subshell environment.
If the \fBlastpipe\fP option is enabled using the \fBshopt\fP builtin
(see the description of \fBshopt\fP below),
the last element of a pipeline may be run by the shell process.
the last element of a pipeline may be run by the shell process
when job control is not active.
.SS Lists
A \fIlist\fP is a sequence of one or more pipelines separated by one
of the operators
......
......@@ -695,7 +695,8 @@ Each command in a pipeline is executed in its own subshell, which is a
separate process (@pxref{Command Execution Environment}).
If the @code{lastpipe} option is enabled using the @code{shopt} builtin
(@pxref{The Shopt Builtin}),
the last element of a pipeline may be run by the shell process.
the last element of a pipeline may be run by the shell process
when job control is not active.
The exit
status of a pipeline is the exit status of the last command in the
......
......@@ -30,6 +30,7 @@
#include "bashtypes.h"
#include <errno.h>
#include <time.h>
#include <limits.h>
#include "typemax.h"
#include <sys/socket.h>
......@@ -44,7 +45,6 @@ int
accept_builtin (list)
WORD_LIST *list;
{
WORD_LIST *l;
SHELL_VAR *v;
intmax_t iport;
int opt;
......
......@@ -4452,21 +4452,24 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
func = find_function (words->word->word);
}
/* In POSIX mode, assignment errors in the temporary environment cause a
non-interactive shell executing a special builtin to exit and a non-
interactive shell to otherwise jump back to the top level. This is what
POSIX says to do for variable assignment errors, and errors in assigning
to the temporary environment are treated as variable assignment errors. */
/* What happens in posix mode when an assignment preceding a command name
fails. This should agree with the code in execute_cmd.c:
do_assignment_statements(), even though I don't think it's executed any
more. */
if (posixly_correct && tempenv_assign_error)
{
#if defined (DEBUG)
/* I don't know if this clause is ever executed, so let's check */
itrace("execute_simple_command: posix mode tempenv assignment error");
#endif
last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX)
jump_to_top_level ((interactive_shell == 0) ? ERREXIT : DISCARD);
jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
#else
if (interactive_shell == 0 && builtin_is_special)
jump_to_top_level (ERREXIT);
jump_to_top_level (FORCE_EOF);
else if (interactive_shell == 0)
jump_to_top_level (DISCARD);
jump_to_top_level (DISCARD); /* XXX - maybe change later */
else
jump_to_top_level (DISCARD);
#endif
......
......@@ -119,10 +119,10 @@ void udequote_pathname PARAMS((char *));
#if HANDLE_MULTIBYTE
void wcdequote_pathname PARAMS((wchar_t *));
static void wdequote_pathname PARAMS((char *));
static void dequote_pathname PARAMS((char *));
#else
# define dequote_pathname udequote_pathname
#endif
static void dequote_pathname PARAMS((char *));
static int glob_testdir PARAMS((char *, int));
static char **glob_dir_to_array PARAMS((char *, char **, int));
......
......@@ -1207,13 +1207,36 @@ history_expand (char *hstring, char **output)
characters in history_no_expand_chars, then it is not a
candidate for expansion of any kind. */
if (cc == 0 || member (cc, history_no_expand_chars) ||
(dquote && cc == '"') ||
(history_inhibit_expansion_function && (*history_inhibit_expansion_function) (string, i)))
(dquote && cc == '"'))
{
ADD_CHAR (string[i]);
break;
}
/* If the application has defined a function to determine whether
or not a history expansion should be performed, call it here. */
/* We check against what we've expanded so far, with the current
expansion appended, because that seems to be what csh does. We
decide to expand based on what we have to this point, not what
we started with. */
if (history_inhibit_expansion_function)
{
int save_j, temp;
save_j = j;
ADD_CHAR (string[i]);
ADD_CHAR (cc);
temp = (*history_inhibit_expansion_function) (result, save_j);
if (temp)
{
result[--j] = '\0'; /* `unadd' cc, leaving ADD_CHAR(string[i]) */
break;
}
else
result[j = save_j] = '\0';
}
#if defined (NO_BANG_HASH_MODIFIERS)
/* There is something that is listed as a `word specifier' in csh
documentation which means `the expanded text to this point'.
......
......@@ -6493,10 +6493,8 @@ parse_string_to_word_list (s, flags, whom)
old_expand_aliases = expand_aliases;
push_stream (1);
#if 0 /* TAG: bash-5.2 Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com> 11/17/2020 */
if (ea = expanding_alias ())
parser_save_alias ();
#endif
last_read_token = WORD; /* WORD to allow reserved words here */
current_command_line_count = 0;
echo_input_at_read = expand_aliases = 0;
......@@ -6531,10 +6529,8 @@ parse_string_to_word_list (s, flags, whom)
last_read_token = '\n';
pop_stream ();
#if 0 /* TAG: bash-5.2 */
if (ea)
parser_restore_alias ();
#endif
#if defined (HISTORY)
remember_on_history = old_remember_on_history;
......
......@@ -361,6 +361,8 @@ static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *))
static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
static int do_assignment_statements PARAMS((WORD_LIST *, char *, int));
/* **************************************************************** */
/* */
/* Utility Functions */
......@@ -11966,6 +11968,87 @@ shell_expand_word_list (tlist, eflags)
return (new_list);
}
/* Perform assignment statements optionally preceding a command name COMMAND.
If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
variable assignment errors. */
static int
do_assignment_statements (varlist, command, is_nullcmd)
WORD_LIST *varlist;
char *command;
int is_nullcmd;
{
WORD_LIST *temp_list;
char *savecmd;
sh_wassign_func_t *assign_func;
int is_special_builtin, is_builtin_or_func, tint;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
environment (do_word_assignment). */
assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
tempenv_assign_error = 0;
is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
/* Posix says that special builtins exit if a variable assignment error
occurs in an assignment preceding it. (XXX - this is old -- current Posix
says that any variable assignment error causes a non-interactive shell
to exit. See the STRICT_POSIX checks below. */
is_special_builtin = posixly_correct && command && find_special_builtin (command);
savecmd = this_command_name;
for (temp_list = varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
assigning_in_environment = is_nullcmd == 0;
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
assigning_in_environment = 0;
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells running
in posix mode cause the shell to exit. */
if (tint == 0)
{
if (is_nullcmd) /* assignment statement */
{
last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX)
if (posixly_correct && interactive_shell == 0)
#else
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
#endif
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
/* In posix mode, assignment errors in the temporary environment
cause a non-interactive shell executing a special builtin to
exit and a non-interactive shell to otherwise jump back to the
top level. This is what POSIX says to do for variable assignment
errors, and POSIX says errors in assigning to the temporary
environment are treated as variable assignment errors.
(XXX - this is not what current POSIX says - look at the
STRICT_POSIX defines. */
else if (posixly_correct)
{
last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX)
exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
#else
if (interactive_shell == 0 && is_special_builtin)
exp_jump_to_top_level (FORCE_EOF);
else if (interactive_shell == 0)
exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
else
exp_jump_to_top_level (DISCARD);
#endif
}
else
tempenv_assign_error++;
}
}
return (tempenv_assign_error);
}
/* The workhorse for expand_words () and expand_words_no_vars ().
First arg is LIST, a WORD_LIST of words.
Second arg EFLAGS is a flags word controlling which expansions are
......@@ -11985,8 +12068,6 @@ expand_word_list_internal (list, eflags)
int eflags;
{
WORD_LIST *new_list, *temp_list;
int tint;
char *savecmd;
tempenv_assign_error = 0;
if (list == 0)
......@@ -11999,30 +12080,11 @@ expand_word_list_internal (list, eflags)
if (new_list == 0)
{
if (subst_assign_varlist)
{
/* All the words were variable assignments, so they are placed
into the shell's environment. */
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
savecmd = this_command_name;
this_command_name = (char *)NULL; /* no arithmetic errors */
tint = do_word_assignment (temp_list->word, 0);
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells
running in Posix.2 mode cause the shell to exit, unless
they are being run by the `command' builtin. */
if (tint == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
}
dispose_words (subst_assign_varlist);
subst_assign_varlist = (WORD_LIST *)NULL;
}
do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
dispose_words (subst_assign_varlist);
subst_assign_varlist = (WORD_LIST *)NULL;
return ((WORD_LIST *)NULL);
}
}
......@@ -12056,49 +12118,7 @@ expand_word_list_internal (list, eflags)
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
{
sh_wassign_func_t *assign_func;
int is_special_builtin, is_builtin_or_func;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
environment. */
assign_func = new_list ? assign_in_env : do_word_assignment;
tempenv_assign_error = 0;
is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
/* Posix says that special builtins exit if a variable assignment error
occurs in an assignment preceding it. */
is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
savecmd = this_command_name;
this_command_name = (char *)NULL;
assigning_in_environment = (assign_func == assign_in_env);
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
assigning_in_environment = 0;
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells running
in Posix.2 mode cause the shell to exit. */
if (tint == 0)
{
if (assign_func == do_word_assignment)
{
last_command_exit_value = EXECUTION_FAILURE;
if (interactive_shell == 0 && posixly_correct)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
else if (interactive_shell == 0 && is_special_builtin)
{
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level (FORCE_EOF);
}
else
tempenv_assign_error++;
}
}
do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
dispose_words (subst_assign_varlist);
subst_assign_varlist = (WORD_LIST *)NULL;
......
......@@ -2,6 +2,7 @@ alias: 0
alias: 0
./alias.tests: line 38: qfoo: command not found
quux
hi
bar
value
bar
......
......@@ -49,6 +49,14 @@ foo bar
unalias foo bar baz
# post bash-5.1 problems with compound array assignment during multiline
# alias expansion
alias foo='a=() b=""
for i in 1; do echo hi; done'
foo
unalias foo
${THIS_SH} ./alias1.sub
${THIS_SH} ./alias2.sub
${THIS_SH} ./alias3.sub
......
......@@ -176,12 +176,14 @@ after non-special builtin: 0
./errors7.sub: line 25: x: readonly variable
after special builtin: 0
./errors7.sub: line 27: x: readonly variable
./errors7.sub: line 29: x: readonly variable
./errors7.sub: line 21: x: readonly variable
after no such command: 1
./errors7.sub: line 23: x: readonly variable
after non-special builtin: 1
./errors7.sub: line 25: x: readonly variable
./errors7.sub: line 27: x: readonly variable
./errors7.sub: line 29: x: readonly variable
./errors8.sub: eval: line 7: syntax error: unexpected end of file
ok 1
./errors8.sub: line 8: v: readonly variable
......
......@@ -26,3 +26,5 @@ echo after non-special builtin: $?
echo after special builtin: $? )
( x=8 $nocmd
echo after assignment error: $? )
( x=8
echo after assignment statement error: $? )
......@@ -21,6 +21,8 @@ cd $DIR
touch a .b
LC_COLLATE=C # fix sort order
echo @(?|.?)
echo @(.?|?)
echo ? .?
......
......@@ -5676,7 +5676,7 @@ pop_args ()
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
ce = array_shift (bash_argc_a, 1, 0);
ce = array_unshift_element (bash_argc_a);
if (ce == 0 || legal_number (element_value (ce), &i) == 0)
i = 0;
......@@ -6286,8 +6286,7 @@ set_pipestatus_array (ps, nproc)
if (array_num_elements (a) == nproc && nproc == 1)
{
ae = element_forw (a->head);
free (element_value (ae));
set_element_value (ae, itos (ps[0]));
ARRAY_ELEMENT_REPLACE (ae, itos (ps[0]));
}
else if (array_num_elements (a) <= nproc)
{
......@@ -6296,8 +6295,7 @@ set_pipestatus_array (ps, nproc)
for (i = 0; i < array_num_elements (a); i++)
{
ae = element_forw (ae);
free (element_value (ae));
set_element_value (ae, itos (ps[i]));
ARRAY_ELEMENT_REPLACE (ae, itos (ps[i]));
}
/* add any more */
for ( ; i < nproc; i++)
......@@ -6310,7 +6308,7 @@ set_pipestatus_array (ps, nproc)
{
/* deleting elements. it's faster to rebuild the array. */
array_flush (a);
for (i = 0; ps[i] != -1; i++)
for (i = 0; i < nproc; i++)
{
t = inttostr (ps[i], tbuf, sizeof (tbuf));
array_insert (a, i, t);
......