fix for rare readline case where read(2) succeeds but also gets a signal as it is returning to user mode; fix for bash completion filename quoting when there is more than one match

This commit is contained in:
Chet Ramey
2025-08-22 16:10:45 -04:00
parent 0864568359
commit ab17ddb7af
4 changed files with 63 additions and 21 deletions
+25
View File
@@ -11625,3 +11625,28 @@ lib/readline/isearch.c
anything else that would cause signals to be processed.
Report and fix from Grisha Levit <grishalevit@gmail.com> based on
a report from penguin p <tgckpg@gmail.com>
8/21
----
lib/readline/input.c
- rl_getc: it is possible, though extremely unlikely, for read(2)
to both succeed (result == 1) and receive a signal
(_rl_caught_signal != 0).
We know we have a signal we're interested in, since readline's
handler was called, so we want to handle it immediately and defer
returning the character we read until the next time through the loop.
From a report from penguin p <tgckpg@gmail.com>
- rl_getc: if the application's SIGINT signal handler returns without
longjmping or exiting the program, make sure to abort out of
searches and numeric arguments, because the readline signal handler
has freed necessary state. Previously we did this only for the
callback interface
8/22
----
bashline.c
- bash_quote_filename: only check whether the file exists and change
the quote character accordingly if we have a single match.
Otherwise, it's a prefix and likely doesn't exist, so we'll stick
with the default backslash completion quoting style.
Fixes completion quoting issue from Aaron Laws <dartme18@gmail.com>
+3 -1
View File
@@ -4415,9 +4415,11 @@ bash_quote_filename (char *s, int rtype, char *qcp)
quoted correctly using backslashes (a backslash-newline pair is
special to the shell parser). */
expchar = nextch = closer = 0;
/* Only check whether the file exists if we're quoting a single completion.
Otherwise, it's a common prefix and probably doesn't exist. */
if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && dircomplete_expand == 0 &&
(expchar = bash_check_expchar (s, 0, &nextch, &closer)) &&
file_exists (s) == 0)
rtype == SINGLE_MATCH && file_exists (s) == 0)
{
/* If it looks like the name is subject to expansion, see if we want to
double-quote it. */
+35 -7
View File
@@ -825,8 +825,14 @@ rl_read_key (void)
{
if (rl_get_char (&c) == 0)
c = (*rl_getc_function) (rl_instream);
/* fprintf(stderr, "rl_read_key: calling RL_CHECK_SIGNALS: _rl_caught_signal = %d\r\n", _rl_caught_signal); */
if (_rl_caught_signal)
{
fprintf(stderr, "rl_read_key: calling RL_CHECK_SIGNALS: c = %d _rl_caught_signal = %d\r\n", c, _rl_caught_signal);
if (c > 0)
rl_stuff_char (c);
c = -1;
RL_CHECK_SIGNALS ();
}
}
}
@@ -837,13 +843,14 @@ int
rl_getc (FILE *stream)
{
int result, ostate, osig;
unsigned char c;
unsigned char c, savec;
int fd;
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
sigset_t empty_set;
fd_set readfds;
#endif
savec = 0;
fd = fileno (stream);
while (1)
{
@@ -859,12 +866,19 @@ rl_getc (FILE *stream)
chance to react or abort some current operation that gets cleaned
up by rl_callback_sigcleanup(). If not, we'll just run through the
loop again. */
if (osig != 0 && (ostate & RL_STATE_CALLBACK))
if (osig != 0 && (ostate & RL_STATE_CALLBACK)) /* XXX - when not in callback mode also? */
goto postproc_signal;
#endif
/* We know at this point that _rl_caught_signal == 0 */
if (savec > 0)
{
c = savec;
savec = 0;
return c;
}
#if defined (__MINGW32__)
if (isatty (fd))
return (_getch ()); /* "There is no error return." */
@@ -888,6 +902,20 @@ rl_getc (FILE *stream)
if (result >= 0)
result = read (fd, &c, sizeof (unsigned char));
/* fprintf(stderr, "rl_getc: read result = %d errno = %d _rl_caught_signal = %d\n", result, errno, _rl_caught_signal); */
/* It is possible, though extremely unlikely, for read to both succeed
(result == 1) and receive a signal (_rl_caught_signal != 0). We
know we have a signal we're interested in, since readline's handler
was called, so we want to handle it below and defer returning the
character we read until the next time through the loop. */
if (result > 0 && _rl_caught_signal != 0)
{
if (c > 0) /* if result == 1 we assume that c is valid */
savec = c; /* one level of pushback */
result = -1;
errno = EINTR;
}
if (result == sizeof (unsigned char))
return (c);
@@ -923,7 +951,7 @@ rl_getc (FILE *stream)
#undef X_EWOULDBLOCK
#undef X_EAGAIN
/* fprintf(stderr, "rl_getc: result = %d errno = %d\n", result, errno); */
/* fprintf(stderr, "rl_getc: read result = %d errno = %d _rl_caught_signal = %d\n", result, errno, _rl_caught_signal); */
/* Handle errors here. */
osig = _rl_caught_signal;
@@ -975,11 +1003,11 @@ postproc_signal:
call the application's signal event hook. */
if (rl_signal_event_hook)
(*rl_signal_event_hook) ();
#if defined (READLINE_CALLBACKS)
else if (osig == SIGINT && (ostate & RL_STATE_CALLBACK) && (ostate & (RL_STATE_ISEARCH|RL_STATE_NSEARCH|RL_STATE_NUMERICARG)))
/* If the application's SIGINT handler returns, make sure we abort out of
searches and numeric arguments because we've freed necessary state. */
if (osig == SIGINT && (ostate & (RL_STATE_ISEARCH|RL_STATE_NSEARCH|RL_STATE_NUMERICARG)))
/* just these cases for now */
_rl_abort_internal ();
#endif
}
}
-13
View File
@@ -1,13 +0,0 @@
# shell functions to include in multiple test files
# squeeze out blanks to avoid white space differences in od implementations
_intl_normalize_spaces()
{
sed -e 's/[[:space:]]\{1,\}/ /g' -e 's/[[:space:]]*$//'
}
# avoid whitespace differences in wc implementations
_cut_leading_spaces()
{
sed -e 's/^[ ]*//g'
}