From: Chet Ramey Date: Fri, 22 Aug 2025 20:10:45 +0000 (-0400) Subject: fix for rare readline case where read(2) succeeds but also gets a signal as it is... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ab17ddb7af948ee6e1a6370aac4ee57b4179cd9c;p=thirdparty%2Fbash.git 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 --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 7d0ececa..e0484010 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -11625,3 +11625,28 @@ lib/readline/isearch.c anything else that would cause signals to be processed. Report and fix from Grisha Levit based on a report from penguin p + + 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 + - 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 diff --git a/bashline.c b/bashline.c index a980718f..1ee70358 100644 --- a/bashline.c +++ b/bashline.c @@ -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. */ diff --git a/lib/readline/input.c b/lib/readline/input.c index 3383edb6..83cf3504 100644 --- a/lib/readline/input.c +++ b/lib/readline/input.c @@ -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 } } diff --git a/tests/test-glue-functions b/tests/test-glue-functions deleted file mode 100644 index 07ad8215..00000000 --- a/tests/test-glue-functions +++ /dev/null @@ -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' -}