From 013fae2c98f5a74f5b5a72f39eb3acc343c6102f Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 18 Sep 2025 17:35:34 -0400 Subject: [PATCH] fix for invalid bracketed paste prefix when the final character is wrong; fixes for unlikely SIGINTs while readline is reading from the keyboard; android fix for generating $'...' strings in the presence of invalid multibyte characters --- CWRU/CWRU.chlog | 42 ++++++++++++++++++++++++--- builtins/declare.def | 4 +++ lib/readline/input.c | 12 ++++---- lib/readline/kill.c | 12 +++++--- lib/readline/text.c | 12 ++++++-- lib/sh/strtrans.c | 67 ++++++++++++++++++++------------------------ 6 files changed, 95 insertions(+), 54 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 6c73a4fc..8d453e0c 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -11723,10 +11723,11 @@ lib/readline/macro.c reading input from a bound macro. Suggested by Grisha Levit -lib/readline/readline.c,lib/readline/text.c - - _rl_dispatch_subseq,_rl_insert_next,_rl_char_search: if we're - defining a keyboard macro, don't insert the expanded value of a - macro that is bound to a key sequence added to the keyboard macro +lib/readline/readline.c,lib/readline/text.c,lib/readline/kill.c + - _rl_dispatch_subseq,_rl_insert_next,_rl_char_search, + _rl_bracketed_text: if we're defining a keyboard macro, don't + insert the expanded value of a macro that is bound to a key + sequence added to the keyboard macro Report and patch from Grisha Levit 9/12 @@ -11734,3 +11735,36 @@ lib/readline/readline.c,lib/readline/text.c builtins/mkbuiltins.c - some minor code cleanups Patch from Martin D Kealey + + 9/15 + ---- +lib/readline/kill.c + - _rl_read_bracketed_paste_prefix: if we read the bracketed paste + prefix except for the last character (key != BRACK_PASTE_LAST), + return 0, since we didn't read a valid prefix + Report from Grisha Levit + - _rl_bracketed_text: if _rl_read_key returns < 0, abort trying + to read the string + +lib/readline/text.c + - _rl_readstr_init: set _rl_rscxt after we finish initializing cxt, + before the call to rl_message + Report from Grisha Levit + - _rl_readstr_getchar: if _rl_read_mbstring returns and _rl_caught_signal + is != 0, treat this as a failure and return -1 after handling the + signal + - _rl_read_command_name: if _rl_readstr_getchar returns -1, but + _rl_rscxt is NULL, assume this was the result of a signal and call + _rl_abort_internal accordingly + Report from Grisha Levit + +lib/readline/input.c + - rl_getc: skip trying to read a character if we have a signal pending + when we enter this function in all cases, not just callback mode. + Suggestion from Grisha Levit + +lib/sh/strtrans.c + - ansic_quote: handle the undefined state of the internal state + pointer when encountering an invalid wide character by using our + own mbstate_t and reinitializing it on EILSEQ. + Report and patch from Grisha Levit diff --git a/builtins/declare.def b/builtins/declare.def index a8284daa..b8c6f966 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -44,11 +44,15 @@ Options which set attributes: -A to make NAMEs associative arrays (if supported) #endif -i to make NAMEs have the `integer' attribute +#ifdef CASEMOD_ATTRS -l to convert the value of each NAME to lower case on assignment +#endif -n make NAME a reference to the variable named by its value -r to make NAMEs readonly -t to make NAMEs have the `trace' attribute +#ifdef CASEMOD_ATTRS -u to convert the value of each NAME to upper case on assignment +#endif -x to make NAMEs export Using `+' instead of `-' turns off the given attribute, except for a, diff --git a/lib/readline/input.c b/lib/readline/input.c index aecc6fc7..b2072122 100644 --- a/lib/readline/input.c +++ b/lib/readline/input.c @@ -859,16 +859,14 @@ rl_getc (FILE *stream) RL_CHECK_SIGNALS (); -#if defined (READLINE_CALLBACKS) - /* Do signal handling post-processing here, but just in callback mode - for right now because the signal cleanup can change some of the + /* Do signal handling post-processing here, not just in callback mode + now, because the signal cleanup can change some of the readline and callback state, and we need to either let the application have a 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)) /* XXX - when not in callback mode also? */ + up by rl_callback_sigcleanup() or another signal cleanup function. + If not, we'll just run through the loop again. */ + if (osig != 0) goto postproc_signal; -#endif /* We know at this point that _rl_caught_signal == 0 */ diff --git a/lib/readline/kill.c b/lib/readline/kill.c index ca92ea13..9d3bdb48 100644 --- a/lib/readline/kill.c +++ b/lib/readline/kill.c @@ -1,6 +1,6 @@ /* kill.c -- kill ring management. */ -/* Copyright (C) 1994-2024 Free Software Foundation, Inc. +/* Copyright (C) 1994-2025 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -718,7 +718,7 @@ _rl_bracketed_text (size_t *lenp) RL_SETSTATE (RL_STATE_MOREINPUT); while ((c = rl_read_key ()) >= 0) { - if (RL_ISSTATE (RL_STATE_MACRODEF)) + if (RL_ISSTATE (RL_STATE_MACRODEF) && RL_ISSTATE (RL_STATE_MACROINPUT) == 0) _rl_add_macro_char (c); if (c == '\r') /* XXX */ @@ -736,7 +736,11 @@ _rl_bracketed_text (size_t *lenp) } } RL_UNSETSTATE (RL_STATE_MOREINPUT); - + if (c < 0) /* read error */ + { + free (buf); + _rl_abort_internal (); + } if (len == cap) buf = xrealloc (buf, cap + 1); buf[len] = '\0'; @@ -790,7 +794,7 @@ _rl_read_bracketed_paste_prefix (int c) break; } - if (ind < BRACK_PASTE_SLEN-1) /* read incomplete sequence */ + if (ind < BRACK_PASTE_SLEN-1 || key != BRACK_PASTE_LAST) /* read incomplete sequence */ { while (ind >= 0) _rl_unget_char (pbuf[ind--]); diff --git a/lib/readline/text.c b/lib/readline/text.c index e3ae28e1..9b00a6f1 100644 --- a/lib/readline/text.c +++ b/lib/readline/text.c @@ -39,6 +39,7 @@ # include #endif +#include #include /* System-specific feature definitions and include files. */ @@ -2029,11 +2030,11 @@ _rl_readstr_init (int pchar, int flags) RL_SETSTATE (RL_STATE_READSTR); cxt->flags |= READSTR_FREEPMT; + _rl_rscxt = cxt; + rl_message ("%s", p); xfree (p); - _rl_rscxt = cxt; - return cxt; } @@ -2081,7 +2082,7 @@ _rl_readstr_getchar (_rl_readstr_cxt *cxt) RL_SETSTATE(RL_STATE_MOREINPUT); c = cxt->lastc = rl_read_key (); RL_UNSETSTATE(RL_STATE_MOREINPUT); - + #if defined (HANDLE_MULTIBYTE) /* This ends up with C (and LASTC) being set to the last byte of the multibyte character. In most cases c == lastc == mb[0] */ @@ -2089,6 +2090,9 @@ _rl_readstr_getchar (_rl_readstr_cxt *cxt) c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX); #endif + if (_rl_caught_signal == SIGINT) /* XXX maybe more signals here */ + c = -1; + RL_CHECK_SIGNALS (); return c; } @@ -2331,6 +2335,8 @@ _rl_read_command_name () if (c < 0) { + if (_rl_rscxt == 0) /* signal */ + _rl_abort_internal (); _rl_readstr_restore (cxt); _rl_readstr_cleanup (cxt, r); return NULL; diff --git a/lib/sh/strtrans.c b/lib/sh/strtrans.c index af75dcfa..5a5e9244 100644 --- a/lib/sh/strtrans.c +++ b/lib/sh/strtrans.c @@ -227,30 +227,24 @@ ansic_quote (const char *str, int flags, int *rlen) { char *r, *ret; const char *s; - size_t l, rsize; unsigned char c; +#if defined (HANDLE_MULTIBYTE) size_t clen; int b; -#if defined (HANDLE_MULTIBYTE) wchar_t wc; + DECLARE_MBSTATE; #endif if (str == 0 || *str == 0) return ((char *)0); - l = strlen (str); - rsize = 4 * l + 4; - r = ret = (char *)xmalloc (rsize); + r = ret = (char *)xmalloc (4 * strlen (str) + 4); *r++ = '$'; *r++ = '\''; for (s = str; c = *s; s++) { - b = 1; /* 1 == add backslash; 0 == no backslash */ - l = 1; - clen = 1; - switch (c) { case ESC: c = 'E'; break; @@ -266,37 +260,38 @@ ansic_quote (const char *str, int flags, int *rlen) break; default: #if defined (HANDLE_MULTIBYTE) - b = is_basic (c); - /* XXX - clen comparison to 0 is dicey */ - if ((b == 0 && ((clen = mbrtowc (&wc, s, MB_CUR_MAX, 0)) < 0 || MB_INVALIDCH (clen) || iswprint (wc) == 0)) || - (b == 1 && ISPRINT (c) == 0)) -#else - if (ISPRINT (c) == 0) -#endif + if (is_basic (c) == 0) { - *r++ = '\\'; - *r++ = TOCHAR ((c >> 6) & 07); - *r++ = TOCHAR ((c >> 3) & 07); - *r++ = TOCHAR (c & 07); - continue; + clen = mbrtowc (&wc, s, MB_CUR_MAX, &state); + if (clen == 0) + break; + if (MB_INVALIDCH (clen)) + INITIALIZE_MBSTATE; + else if (iswprint (wc)) + { + for (b = 0; b < (int)clen; b++) + *r++ = (unsigned char)s[b]; + s += clen - 1; /* -1 because of the increment above */ + continue; + } } - l = 0; - break; + else +#endif + if (ISPRINT (c)) + { + *r++ = c; + continue; + } + + *r++ = '\\'; + *r++ = TOCHAR ((c >> 6) & 07); + *r++ = TOCHAR ((c >> 3) & 07); + *r++ = TOCHAR (c & 07); + continue; } - if (b == 0 && clen == 0) - break; - if (l) - *r++ = '\\'; - - if (clen == 1) - *r++ = c; - else - { - for (b = 0; b < (int)clen; b++) - *r++ = (unsigned char)s[b]; - s += clen - 1; /* -1 because of the increment above */ - } + *r++ = '\\'; + *r++ = c; } *r++ = '\''; -- 2.47.3