fix to make verbose mode print lines as they're read while parsing a multi-line command substitution; change to readline so that it no longer treats SIGTERM causing an immediate exit, so bash can trap it in interactive shells; fix potential integer overflow on command substitution output larger than 2GB; make trap action execution ignore any current break and continue conditions, so actions are always executed even if break or continue was executed before the trap was handled

This commit is contained in:
Chet Ramey committed 2026-10-23 16:37:32 -04:00
1 parent 7cfdb340d2
commit 5e427bb15d
10 files changed
+93 -21

No files matched your search

+1 -1
View File
@@ -635,7 +635,7 @@ jj. Asynchronous commands now always set $? to 0 and are not affected by
whether or not the command's exit status is being inverted.
kk. Fixed a problem that caused a line ending with an escaped newline and
containingh a prior `eval' to be incorrectly parsed.
containing a prior `eval' to be incorrectly parsed.
ll. Fixed an issue with programmable completion and `!' in extglob patterns
used as arguments to `compgen -X'.
+2 -1
View File
@@ -503,7 +503,8 @@ j. shell-transpose-words: a new bindable readline command that uses the same
k. The shell now adds default bindings for shell-forward-word,
shell-backward-word, shell-transpose-words, and shell-kill-word.
l. Bash now allows ARGV0 appearing in the initial shell environment to set $0.
l. Bash now allows BASH_ARGV0 appearing in the initial shell environment to
set $0.
m. If `unset' is executed without option arguments, bash tries to unset a shell
function if a name argument cannot be a shell variable name because it's not
+1 -1
View File
@@ -534,7 +534,7 @@ dddd. Work around system-specific problems (macOS) where isblank(3) returns
eeee. Fix for crash while parsing alias expansions that include compound
assignments.
ffff. Fixe for non-interactive shells reading a script file that ends with
ffff. Fix for non-interactive shells reading a script file that ends with
backslash preceding EOF.
gggg. Fix to command printing when here-documents are attached to compound
+35
View File
@@ -13430,3 +13430,38 @@ error.c
the `exec' builtin, since the `execfail' shopt is supposed to
inhibit this.
Report from Zev Weiss <zev@bewilderbeest.net>
10/5
----
parse.y
- xparse_dolparen: turn off echo_input_at_read so we don't echo lines
a second time
- shell_getc: if echo_input_at_read is on, echo input lines even if
shell_eof_token is `)' or `}'; rely on the callers to make sure it's
off if not wanted (e.g., by xparse_dolparen)
From https://savannah.gnu.org/bugs/?68735
10/13
-----
lib/readline/input.c
- rl_getc: handle receipt of SIGTERM while waiting for input like a
SIGINT (call RL_CHECK_SIGNALS()) instead of SIGHUP. Might need to
explicitly return error/EOF if the application's signal handler is
SIG_IGN for backwards compatibility.
From a report by Denys Vlasenko <dvlasenk@redhat.com>
10/14
-----
stringlib.c,externs.h
- strip_trailing: LEN argument is now size_t to avoid integer overflow
on command substitution strings longer than 2GB
Report from Lilian CRIMET <lilian.crimet@gmail.com>
10/22
-----
trap.c
- run_pending_traps, _run_trap_internal: make sure to set breaking
and continuing to 0 before running the trap action, then restore
them after the action completes. Make sure to handle the case where
the trap action runs break or continue.
From a report by Dimitrios Christou <dimitrios.christou@skillonnet.com>
+1 -2
View File
@@ -4394,7 +4394,7 @@ exec [-cl] [-a @var{name}] [@var{command} [@var{arguments}]]
If @var{command}
is supplied, it replaces the shell without creating a new process.
@var{command} cannot be a shell builtin or function.
The @var{arguments} become the arguments to @var{command}
The @var{arguments} become the arguments to @var{command}.
If the @option{-l} option is supplied, the shell places a dash at the
beginning of the zeroth argument passed to @var{command}.
This is what the @code{login} program does.
@@ -9202,7 +9202,6 @@ Readline,
and is ignored and removed otherwise,
so it shouldn't be used in @env{PS0} or @env{PS4},
or when line editing is not enabled.
@item \]
End a sequence of non-printing characters begun with @samp{\[}
@end table
+1 -1
View File
@@ -174,7 +174,7 @@ extern char *substring (const char *, size_t, size_t);
extern char *strsub (const char *, const char *, const char *, int);
extern char *strcreplace (const char *, int, const char *, int);
extern void strip_leading (char *);
extern void strip_trailing (char *, int, int);
extern void strip_trailing (char *, size_t, int);
extern int str_firstdiff (const char *, const char *);
extern int str_lastsame (const char *, const char *);
+10 -6
View File
@@ -958,18 +958,22 @@ rl_getc (FILE *stream)
/* If the error that we received was EINTR, then try again,
this is simply an interrupted system call to read (). We allow
the read to be interrupted if we caught SIGHUP, SIGTERM, or any
of the other signals readline treats specially. If the
application sets an event hook, call it for other signals.
of the other signals readline treats specially. SIGHUP causes an
immediate error/EOF return; the other signals call back to the
application through RL_CHECK_SIGNALS.
If the application sets an event hook, call it for other signals.
Otherwise (not EINTR), some error occurred, also signifying EOF. */
if (errno != EINTR)
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
/* fatal signals of interest */
#if defined (SIGHUP)
else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
#else
else if (_rl_caught_signal == SIGTERM)
#endif
else if (_rl_caught_signal == SIGHUP)
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
#endif
else if (_rl_caught_signal == SIGTERM)
/* Allow the application to handle or exit instead of error/EOF */
RL_CHECK_SIGNALS ();
/* keyboard-generated signals of interest */
#if defined (SIGQUIT)
else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT)
+15 -7
View File
@@ -453,7 +453,7 @@ inputunit: simple_list simple_list_terminator
| funsub
{
/* This is special; look at the production and how
parse_comsub/parse_valsub sets token_to_read */
parse_comsub sets token_to_read */
global_command = $1;
YYACCEPT;
}
@@ -2713,15 +2713,18 @@ shell_getc (int remove_quoted_newline)
if (shell_input_line)
{
/* Lines that signify the end of the shell's input should not be
echoed. We should not echo lines while parsing command
substitutions with recursive calls into the parsing engine; those
should only be echoed once when we read the word. That is the
reason for the test against shell_eof_token, which is set to a
right paren when parsing the contents of command substitutions. */
echoed. We should echo lines while parsing command and process
substitutions only once: the first time parse_comsub() is called.
Further calls via xparse_dolparen or during parse_and_execute
should not result in echoing input; we rely on the callers to
set echo_input_at_read appropriately. That is the reason for the
test against shell_eof_token, which is probably more elaborate
than is really necessary. */
if (echo_input_at_read && (shell_input_line[0] ||
(shell_input_line_terminator != EOF &&
shell_input_line_terminator != READERR)) &&
shell_eof_token == 0)
/*(*/ (shell_eof_token == 0 ||
((parser_state & PST_EOFTOKEN) && shell_eof_token == ')' || shell_eof_token == '}')))
fprintf (stderr, "%s\n", shell_input_line);
}
else
@@ -4766,6 +4769,10 @@ xparse_dolparen (const char *base, char *string, size_t *indp, int flags)
local_extglob = extended_glob;
#endif
/* We also choose not to echo input at this stage; if verbose is on, the
first call to parse_comsub should echo the input lines. */
echo_input_at_read = 0;
if (funsub && FUNSUB_CHAR (*string) && (*string == '|' || *string == ';'))
string++;
@@ -4787,6 +4794,7 @@ xparse_dolparen (const char *base, char *string, size_t *indp, int flags)
#if defined (EXTENDED_GLOB)
extended_glob = local_extglob;
#endif
echo_input_at_read = verbose_flag;
token_to_read = 0;
simplecmd_lineno = save_lineno;
+1 -1
View File
@@ -259,7 +259,7 @@ strip_leading (char *string)
newlines. If NEWLINES_ONLY is non-zero, only trailing newlines
are removed. STRING should be terminated with a zero. */
void
strip_trailing (char *string, int len, int newlines_only)
strip_trailing (char *string, size_t len, int newlines_only)
{
while (len >= 0)
{
+26 -1
View File
@@ -332,6 +332,7 @@ run_pending_traps (void)
register int sig;
int x;
volatile int old_exit_value, old_running, old_context;
volatile int old_breaking, old_continuing;
WORD_LIST *save_subst_varlist;
HASH_TABLE *save_tempenv;
sh_parser_state_t pstate;
@@ -485,6 +486,10 @@ run_pending_traps (void)
pending_traps[sig] = 0;
evalnest++;
old_breaking = breaking;
old_continuing = continuing;
breaking = continuing = 0;
function_code = 0;
save_return_catch_flag = return_catch_flag;
if (return_catch_flag)
@@ -507,6 +512,12 @@ run_pending_traps (void)
x = return_catch_value;
}
/* what if the trap command runs `break' or `continue'? */
if (breaking == 0 || old_breaking != 0)
breaking = old_breaking;
if (continuing == 0 || old_continuing != 0)
continuing = old_continuing;
evalnest--;
#if defined (JOB_CONTROL)
restore_pipeline (1);
@@ -1074,6 +1085,7 @@ run_exit_trap (void)
pflags = interactive_shell ? SEVAL_NOTIFY : 0;
pflags |= SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE|SEVAL_NOOPTIMIZE;
reset_parser ();
breaking = continuing = 0;
parse_and_execute (trap_command, "exit trap", pflags);
}
else if (code == ERREXIT)
@@ -1133,7 +1145,9 @@ _run_trap_internal (int sig, char *tag)
char *old_trapsig;
int trap_exit_value;
volatile int save_return_catch_flag, function_code;
int old_modes, old_running, old_int, old_context;
volatile int old_running, old_int, old_context;
volatile int old_breaking, old_continuing;
int old_modes;
int flags;
procenv_t save_return_catch;
WORD_LIST *save_subst_varlist;
@@ -1204,6 +1218,10 @@ _run_trap_internal (int sig, char *tag)
/* XXX - set pending_traps[sig] = 0 here? */
evalnest++;
old_breaking = breaking;
old_continuing = continuing;
breaking = continuing = 0;
/* If we're in a function, make sure return longjmps come here, too. */
function_code = 0;
save_return_catch_flag = return_catch_flag;
@@ -1225,6 +1243,13 @@ _run_trap_internal (int sig, char *tag)
}
else
trap_exit_value = return_catch_value;
/* what if the trap command runs `break' or `continue'? */
if (breaking == 0 || old_breaking != 0)
breaking = old_breaking;
if (continuing == 0 || old_continuing != 0)
continuing = old_continuing;
evalnest--;
#if defined (JOB_CONTROL)