From: Chet Ramey Date: Tue, 2 Jun 2026 14:01:54 +0000 (-0400) Subject: remove the [ and ] prompt expansions from prompt strings that are not used with readl... X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fdevel;p=thirdparty%2Fbash.git remove the [ and ] prompt expansions from prompt strings that are not used with readline; fix some redisplay issues when readline does not start in column 0; fix memory leak in unquoted $@ expansion; fix readline redisplay issue after SIGWINCH shrinks the terminal size; fix issue with mapfile that can cause crashes if a callback unsets the array mapfile is using --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index eb8ab19a..7b9aaaf2 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -12938,3 +12938,58 @@ subst.c after they return by adding an unwind-protect function uw_restore_verbose() Report and patch from Grisha Levit + + 5/18 + ---- +doc/bash.1,doc/bashref.texi + - note that PS0 and PS4 are not fed to readline, so they shouldn't + contain the \[ and \] prompt escapes + +parse.y + - decode_prompt_string: if we're decoding a prompt string (is_prompt == 1), + ignore \[ and \] unless the prompt is PS1 or PS2. + Report from Egmont Koblinger + + 5/19 + ---- +lib/readline/display.c + - rl_redisplay: when deciding whether or not to reprint the prompt from + column 0 because the cursor is before the last invisible character, + use local_prompt_len to compute index into the buffer in a multibyte + locale, since _rl_last_c_pos is a screen position. This still doesn't + fix the eventual redisplay breakage if readline starts with the + cursor somewhere other than column 0 + Fixes issue reported by Lennart Ackermans + + 5/20 + ---- +builtins/getopt.c +examples/loadables/seq.c +lib/sh/mbschr.c,lib/sh/utf8.c +pathexp.c +examples/loadables/seq.c + - fixes for `const' and gcc 15 + Report and patch from Grisha Levit + + 5/21 + ---- +subst.c + - string_list_dollar_atstar: fix memory leak by calling dispose_words(l2) + after the call to word_list_split(l2) + Report from Grisha Levit + + 5/22 + ---- +lib/readline/display.c + - _rl_redisplay_after_sigwinch: call _rl_reset_prompt every time, so + the local_prompt_invis_chars array gets updated along with the + local_prompt_newlines array + Report and fix from Félix Bouynot + + 5/25 + ---- +builtins/mapfile.def + - mapfile: the callback can leave the variable in an inconsistent + state, or even unset it, so we use bind_array_variable to look it + up again every time through the loop + Report and patch from Philippe Grégoire diff --git a/builtins/getopt.c b/builtins/getopt.c index 47a8f77c..9ad08594 100644 --- a/builtins/getopt.c +++ b/builtins/getopt.c @@ -1,6 +1,6 @@ /* getopt.c - getopt for Bash. Used by the getopt builtin. */ -/* Copyright (C) 1993-2009,2022 Free Software Foundation, Inc. +/* Copyright (C) 1993-2009,2022,2026 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -113,7 +113,8 @@ int sh_badopt = 0; int sh_getopt (int argc, char *const *argv, const char *optstring) { - char c, *temp; + char c; + const char *temp; sh_optarg = 0; diff --git a/builtins/mapfile.def b/builtins/mapfile.def index 31528fa8..71fb8196 100644 --- a/builtins/mapfile.def +++ b/builtins/mapfile.def @@ -153,9 +153,7 @@ mapfile (int fd, long line_count_goal, long origin, long nskip, long callback_qu line_length = 0; unbuffered_read = 0; - /* The following check should be done before reading any lines. Doing it - here allows us to call bind_array_element instead of bind_array_variable - and skip the variable lookup on every call. */ + /* The following check should be done before reading any lines. */ entry = builtin_find_indexed_array (array_name, flags & MAPF_CLEARARRAY); if (entry == 0) return EXECUTION_FAILURE; @@ -201,8 +199,13 @@ mapfile (int fd, long line_count_goal, long origin, long nskip, long callback_qu run_callback (callback, array_index, line); } - /* XXX - bad things can happen if the callback modifies ENTRY, e.g., - unsetting it or changing it to a non-indexed-array type. */ + /* Bad things can happen if the callback modifies ENTRY, e.g., + unsetting it or changing it to a non-indexed-array type, so we + look it up again every time we need to assign something */ + entry = bind_array_variable (array_name, array_index, line, 0); + if (entry == 0 || ASSIGN_DISALLOWED (entry, 0)) + return EXECUTION_FAILURE; + bind_array_element (entry, array_index, line, 0); /* Have we exceeded # of lines to store? */ diff --git a/doc/bash.1 b/doc/bash.1 index 6e470409..de4a49b5 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,7 +5,7 @@ .\" Case Western Reserve University .\" chet.ramey@case.edu .\" -.\" Last Change: Wed May 6 16:08:33 EDT 2026 +.\" Last Change: Mon May 18 11:35:35 EDT 2026 .\" .\" For bash_builtins, strip all but "SHELL BUILTIN COMMANDS" section .\" For rbash, strip all but "RESTRICTED SHELL" section @@ -22,7 +22,7 @@ .ds zX \" empty .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2026 May 6" "GNU Bash 5.3" +.TH BASH 1 "2026 May 18" "GNU Bash 5.3" .\" .ie \n(.g \{\ .ds ' \(aq @@ -4328,7 +4328,8 @@ is invalid, .B bash prints a message to standard error indicating failure, does not perform the substitution, -and does not execute the command associated with the expansion. +and does not +continue to execute the command in which the error occurs. .SS Process Substitution \fIProcess substitution\fP allows a process's input or output to be referred to using a filename. @@ -4336,7 +4337,9 @@ It takes the form of \fB<(\fP\fIlist\^\fP\fB)\fP or \fB>(\fP\fIlist\^\fP\fB)\fP. -The process \fIlist\fP is run asynchronously, and its input or output +The process \fIlist\fP, +as long as it is not a null command without redirections, +is run asynchronously, and its input or output appears as a filename. This filename is passed as an argument to the current command as the result of the @@ -6628,9 +6631,12 @@ A backslash. .B \e[ Begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt. +This escape is only useful when the prompt will be supplied to +\fBreadline\fP, so it shouldn't be used in \fBPS0\fP or \fBPS4\fP. .TP .B \e] -End a sequence of non-printing characters. +End a sequence of non-printing characters begun with +.BR \e[ . .PD .RE .PP diff --git a/doc/bashref.texi b/doc/bashref.texi index 06b48832..8f64c8ee 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -2997,7 +2997,8 @@ The evaluation is performed according to the rules listed below If the expression is invalid, Bash prints a message indicating failure to the standard error, does not perform the substitution, -and does not execute the command associated with the expansion. +and does not +continue to execute the command in which the error occurs. @node Process Substitution @subsection Process Substitution @@ -3015,7 +3016,9 @@ or >(@var{list}) @end example @noindent -The process @var{list} is run asynchronously, and its input or output +The process @var{list}, +as long as it is not a null command without redirections, +is run asynchronously, and its input or output appears as a filename. This filename is passed as an argument to the current command as the result of the @@ -9154,8 +9157,11 @@ A backslash. Begin a sequence of non-printing characters. This could be used to embed a terminal control sequence into the prompt. +This escape is only useful when the prompt will be supplied to +Readline, so it shouldn't be used in @env{PS0} or @env{PS4}. + @item \] -End a sequence of non-printing characters. +End a sequence of non-printing characters begun with @samp{\[} @end table The command number and the history number are usually different: diff --git a/doc/version.texi b/doc/version.texi index b3f81be4..9632036b 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2026 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Wed May 6 16:08:14 EDT 2026 +@set LASTCHANGE Mon May 18 11:35:01 EDT 2026 @set EDITION 5.3 @set VERSION 5.3 -@set UPDATED 6 May 2026 +@set UPDATED 18 May 2026 @set UPDATED-MONTH May 2026 diff --git a/examples/loadables/cut.c b/examples/loadables/cut.c index b69e7bd0..d426031a 100644 --- a/examples/loadables/cut.c +++ b/examples/loadables/cut.c @@ -615,6 +615,8 @@ char *cut_doc[] = { "processes to successive elements of ARRAY, beginning at 0. The", "strings cut assigns to ARRAY are identical to the strings it would", "write to the standard output if -a were not supplied.", + "", + "-s stops printing of lines not containing delimiters. -n is ignored.", (char *)NULL }; diff --git a/examples/loadables/seq.c b/examples/loadables/seq.c index 13834b8d..e09576e1 100644 --- a/examples/loadables/seq.c +++ b/examples/loadables/seq.c @@ -1,5 +1,5 @@ /* seq - print sequence of numbers to standard output. - Copyright (C) 2018-2022 Free Software Foundation, Inc. + Copyright (C) 2018-2026 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -171,7 +171,7 @@ static int getprec (const char *numbuf) { int p; - char *dp; + const char *dp; if (dp = strchr (numbuf, decimal_point)) dp++; /* skip over decimal point */ diff --git a/lib/readline/display.c b/lib/readline/display.c index 18e60066..f36cf080 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -1,6 +1,6 @@ /* display.c -- readline redisplay facility. */ -/* Copyright (C) 1987-2025 Free Software Foundation, Inc. +/* Copyright (C) 1987-2026 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. @@ -1497,7 +1497,6 @@ rl_redisplay (void) the characters from the current cursor position. But we only need to reprint it if the cursor is before the last invisible character in the prompt string. */ - /* XXX - why not use local_prompt_len? */ nleft = prompt_visible_length + wrap_offset; if (cursor_linenum == prompt_last_screen_line) { @@ -1509,11 +1508,7 @@ rl_redisplay (void) on the current screen line begins in the buffer. It is a buffer position, an index into curline (local_prompt + pmt_offset) */ - cursor_bufpos = pmt_offset; - if (mb_cur_max == 1 || rl_byte_oriented) - cursor_bufpos += _rl_last_c_pos; - else - cursor_bufpos += _rl_last_c_pos + curline_invchars; + cursor_bufpos = pmt_offset + local_prompt_len; if (local_prompt && local_prompt_invis_chars[cursor_linenum] && _rl_last_c_pos > 0 && @@ -3525,8 +3520,9 @@ _rl_redisplay_after_sigwinch (void) else rl_crlf (); - if (_rl_screenwidth < prompt_visible_length) - _rl_reset_prompt (); /* update local_prompt_newlines array */ + /* Let expand_prompt() update local_prompt_newlines and local_prompt_invis_chars + arrays */ + _rl_reset_prompt (); /* Redraw only the last line of a multi-line prompt. */ t = strrchr (rl_display_prompt, '\n'); diff --git a/lib/sh/mbschr.c b/lib/sh/mbschr.c index f86ea0bb..609c3dc1 100644 --- a/lib/sh/mbschr.c +++ b/lib/sh/mbschr.c @@ -1,6 +1,6 @@ /* mbschr.c - strchr(3) that handles multibyte characters. */ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002-2026 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -81,5 +81,5 @@ mbschr (const char *s, int c) } else #endif - return (strchr (s, c)); + return ((char *)strchr (s, c)); } diff --git a/lib/sh/utf8.c b/lib/sh/utf8.c index c5503301..ab5fdfa7 100644 --- a/lib/sh/utf8.c +++ b/lib/sh/utf8.c @@ -1,6 +1,6 @@ /* utf8.c - UTF-8 character handling functions */ -/* Copyright (C) 2018, 2022 Free Software Foundation, Inc. +/* Copyright (C) 2018, 2022, 2026 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -35,7 +35,7 @@ extern int locale_utf8locale; char * utf8_mbschr (const char *s, int c) { - return strchr (s, c); /* for now */ + return (char *)strchr (s, c); /* for now */ } int diff --git a/parse.y b/parse.y index 2e285d56..cc3e55fe 100644 --- a/parse.y +++ b/parse.y @@ -6632,7 +6632,7 @@ decode_prompt_string (char *string, int is_prompt) #if defined (READLINE) case '[': case ']': - if (no_line_editing) + if (no_line_editing || (is_prompt && decoding_prompt != ps1_prompt && decoding_prompt != ps2_prompt)) { string++; break; diff --git a/pathexp.c b/pathexp.c index 87c49bf3..4618d095 100644 --- a/pathexp.c +++ b/pathexp.c @@ -1,6 +1,6 @@ /* pathexp.c -- The shell interface to the globbing library. */ -/* Copyright (C) 1995-2024 Free Software Foundation, Inc. +/* Copyright (C) 1995-2024,2026 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -525,7 +525,7 @@ static int glob_name_is_acceptable (const char *name) { struct ign *p; - char *n; + const char *n; int flags; /* . and .. are never matched. We extend this to the terminal component of a diff --git a/subst.c b/subst.c index e4dffd34..2b767610 100644 --- a/subst.c +++ b/subst.c @@ -3167,6 +3167,8 @@ string_list_dollar_atstar (WORD_LIST *list, int quoted, int flags) don't want here. */ l = word_list_split (l2); /* pre-split, preserving empty arguments */ + dispose_words (l2); + /* We want to turn words that are QUOTED_NULL with W_HASQUOTEDNULL set in the word flags back into "" but leave every other $'\177' alone. */ for (l2 = l; l2; l2 = l2->next) @@ -3183,7 +3185,6 @@ string_list_dollar_atstar (WORD_LIST *list, int quoted, int flags) free (sep); #endif - dispose_words (l2); dispose_words (l); return ret; @@ -8905,6 +8906,23 @@ get_var_and_type (char *varname, char *value, array_eltstate_t *estatep, int quo *valp = temp ? savestring (temp) : temp; } } +#if 0 /* TAG:bash-5.4 2026/05/11 YourLi@outlook.com */ + /* For ksh93 compatibility, ${!ref} where ref is a non-special, nameref + variable, should expand to the value of ref, without resolving any + nameref chain. Previous versions treated an array variable without a + subscript the same as ref[0] (next clause). */ + else if (shell_compatibility_level > 53 && + want_indir && value && vtype == VT_VARIABLE && + SPECIAL_VAR (varname, 1) == 0 && + (v = find_variable_noref (varname + 1)) && + nameref_p (v)) + { + /* This is for compatibility with ksh93. */ + vtype = VT_VARIABLE; + *varp = v; + *valp = savestring (value); + } +#endif else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) { vtype = VT_ARRAYMEMBER;