From: Chet Ramey Date: Tue, 11 Nov 2025 16:36:53 +0000 (-0500) Subject: minor test suite updates; fix for export string when a variable from a function tempo... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=81d858426873c0b04bde9ed098bd34b6a77591d1;p=thirdparty%2Fbash.git minor test suite updates; fix for export string when a variable from a function temporary environment is converted to an array variable; use fpurge to discard builtin output after a SIGINT in an interactive shell; fix for words containing quoted strings and {forward,backward}-shellword; experimental fix to discard a bgpid when a child with the same pid is created only if the new child is also an asynchronous pid; change read builtin to return >1 on read error, since 1 is reserved for EOF --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 831cf1c9..e9aa8b9e 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -12144,3 +12144,50 @@ variables.c attribute to variables from the temporary environment when `local -n' is executed (for now), return that variable instead of creating a new one + + 10/27 + ----- +tests/unicode1.sub + - report total number of failed tests to avoid script failure if some + tests are skipped due to non-installed locales + +tests/run-all + - use tput for colored output strings if available + Patches from G. Branden Robinson + + 10/28 + ----- +variables.c + - make_local_array_variable,make_local_assoc_variable: call + INVALIDATE_EXPORTSTR in case this is a variable from the function + environment being converted into a local array/assoc variable + Report from Grisha Levit + + 11/5 + ---- +sig.c + - throw_to_top_level: if we get a SIGINT (interrupt_state != 0) in an + interactive shell (interactive != 0), call fpurge to throw away + any pending output to stdout before undoing any redirections + Report from Grisha Levit + +subst.c + - skip_to_delim: if we're trying to skip to the close quote in a single- + or double-quoted string, decrement the index by 1 before returning + it because skip_single_quoted and skip_double_quoted return an + index one past the end of the close quote. + Report from Grisha Levit + + 11/6 + ---- +jobs.c + - make_child: only call bgp_delete on a newly-created pid if that + process is asynchronous, since that is what will cause it to be + put into the bgpids table. This mostly matters for procsubs and + asynchronous jobs, but will happen for comsubs in async jobs + and coprocs as well. + From a report by Kerin Millar + +builtins/read.def + - read_builtin: POSIX says read must return >1 on a read error, 1 + is reserved for EOF diff --git a/MANIFEST b/MANIFEST index 848c495e..7f965be5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1085,6 +1085,7 @@ tests/comsub23.sub f tests/comsub24.sub f tests/comsub25.sub f tests/comsub26.sub f +tests/comsub27.sub f tests/comsub-eof.tests f tests/comsub-eof0.sub f tests/comsub-eof1.sub f diff --git a/builtins/read.def b/builtins/read.def index c6ab8b2d..88c9be8b 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -941,7 +941,7 @@ add_char: run_unwind_frame ("read_builtin"); if (free_ifs) free (ifs_chars); - return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig); + return ((t_errno != EINTR) ? EX_MISCERROR : 128+lastsig); } if (tmsec > 0 || tmusec > 0) diff --git a/doc/bash.1 b/doc/bash.1 index ab307a86..b0fa1ef0 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -3690,7 +3690,7 @@ or when is followed by a character which is not to be interpreted as part of its name. The \fIparameter\fP is a shell parameter as described above -\fBPARAMETERS\fP) or an array reference (\fBArrays\fP). +(\fBPARAMETERS\fP) or an array reference (\fBArrays\fP). .PD .PP If the first character of \fIparameter\fP is an exclamation point (\fB!\fP), @@ -6939,6 +6939,7 @@ file with a statement of the form .PP \fBset\fP \fIvariable\-name\fP \fIvalue\fP .RE +.LP or using the \fBbind\fP builtin command (see .SM .B "SHELL BUILTIN COMMANDS" diff --git a/jobs.c b/jobs.c index dc59635c..07f8ca7a 100644 --- a/jobs.c +++ b/jobs.c @@ -2482,9 +2482,11 @@ make_child (char *command, int flags) been reused. */ delete_old_job (pid); - /* Perform the check for pid reuse unconditionally. Some systems reuse - PIDs before giving a process CHILD_MAX/_SC_CHILD_MAX unique ones. */ - bgp_delete (pid); /* new process, discard any saved status */ + /* Perform the check for background pid reuse unconditionally. + Some systems reuse PIDs before giving a process + CHILD_MAX/_SC_CHILD_MAX unique ones. */ + if (async_p) + bgp_delete (pid); /* new background process, discard any saved status */ last_made_pid = pid; diff --git a/lib/sh/strtrans.c b/lib/sh/strtrans.c index 37addeb8..e3d67b6a 100644 --- a/lib/sh/strtrans.c +++ b/lib/sh/strtrans.c @@ -55,7 +55,7 @@ ansicstr (const char *string, size_t len, int flags, int *sawc, size_t *rlen) const char *s; unsigned long v; size_t clen; - int mb_cur_max; + size_t mb_cur_max; #if defined (HANDLE_MULTIBYTE) wchar_t wc; #endif @@ -82,7 +82,7 @@ ansicstr (const char *string, size_t len, int flags, int *sawc, size_t *rlen) /* We read an entire multibyte character at a time if we are in a locale where a backslash can possibly appear as part of a multibyte character. UTF-8 encodings prohibit this. */ - if (locale_utf8locale == 0 && mb_cur_max > 0 && is_basic (c) == 0) + if (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0) { clen = mbrtowc (&wc, s - 1, mb_cur_max, 0); if (MB_NULLWCH (clen)) diff --git a/sig.c b/sig.c index 6de13259..0662a249 100644 --- a/sig.c +++ b/sig.c @@ -462,6 +462,10 @@ throw_to_top_level (void) unlink_fifo_list (); #endif /* PROCESS_SUBSTITUTION */ + /* We don't want any more output after a SIGINT. */ + if (interactive && print_newline) + fpurge (stdout); + run_unwind_protects (); loop_level = continuing = breaking = funcnest = 0; interrupt_execution = retain_fifos = executing_funsub = 0; diff --git a/subst.c b/subst.c index 0e804b76..34754189 100644 --- a/subst.c +++ b/subst.c @@ -2226,6 +2226,13 @@ skip_to_delim (const char *string, int start, const char *delims, int flags) i = skip_single_quoted (string, slen, start, 0); else i = skip_double_quoted (string, slen, start, completeflag); + + /* skip_single_quoted and skip_double_quoted leave point one character + past the end of the quoted string. That doesn't match the semantics + we want here, so we back to the quote char and return that index. */ + if (i > 0) + i--; + CQ_RETURN (i); } diff --git a/tests/README b/tests/README index b023ef60..c00af3b4 100644 --- a/tests/README +++ b/tests/README @@ -1,3 +1,3 @@ -Type `sh run-all'. +Run `make tests' from the bash build directory. Read COPYRIGHT for copyright information. diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 4401d768..f3a23b8f 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -10,14 +10,18 @@ export TMPDIR export BASH_TSTOUT=/tmp/xx rm -f ${BASH_TSTOUT} -# keep track of passed and failed tests and report them if [ -t 1 ]; then - # can't rely on having $'...' or printf understanding \e - # bright red background, white foreground text - export CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + if type -P tput >/dev/null; then + CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) + else + # can't rely on having $'...' or printf understanding \e + # bright red background, white foreground text + CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + fi else - export CSTART= CEND= + CSTART= CEND= fi +export CSTART CEND export TAB=' ' ${THIS_SH} "$@" diff --git a/tests/RUN-TEST-SCRIPT b/tests/RUN-TEST-SCRIPT index 5d962abd..fec43b2d 100755 --- a/tests/RUN-TEST-SCRIPT +++ b/tests/RUN-TEST-SCRIPT @@ -11,12 +11,17 @@ export BASH_TSTOUT=/tmp/xx rm -f ${BASH_TSTOUT} if [ -t 1 ]; then - # can't rely on having $'...' or printf understanding \e - # bright red background, white foreground text - export CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + if type -P tput >/dev/null; then + CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) + else + # can't rely on having $'...' or printf understanding \e + # bright red background, white foreground text + CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + fi else - export CSTART= CEND= + CSTART= CEND= fi +export CSTART CEND export TAB=' ' ${THIS_SH} "$@" diff --git a/tests/comsub2.right b/tests/comsub2.right index 2352303a..6e21c5ca 100644 --- a/tests/comsub2.right +++ b/tests/comsub2.right @@ -201,3 +201,26 @@ after: var = inside after: 42 var = inside var=inside 42 after: 0 var = inside + comsub27.sub +declare -- x="0" +declare -- x="a[]" +declare -- x="a[]" +declare -- x="" +declare -- x="" +a[${ unset x;}] +declare -i x +declare -- x="" +./comsub27.sub: line 36: ${ unset x;}: arithmetic syntax error: operand expected (error token is "${ unset x;}") +declare -i x +declare -- SECONDS="" +declare -i SECONDS="0" +declare -- x="0" +declare -a x=([2]="a[]") +declare -ai a=() +./comsub27.sub: line 61: b[]: bad array subscript +./comsub27.sub: line 61: b[]: bad array subscript +declare -ai a=([0]="1" [1]="0" [2]="3") +declare -Ai a=([0]="" ) +./comsub27.sub: line 71: b[]: bad array subscript +./comsub27.sub: line 71: b[]: bad array subscript +declare -Ai a=([3]="0" [1]="0" ) diff --git a/tests/comsub2.tests b/tests/comsub2.tests index 26d822fd..38fb6171 100644 --- a/tests/comsub2.tests +++ b/tests/comsub2.tests @@ -152,3 +152,4 @@ test_runsub ./comsub23.sub test_runsub ./comsub24.sub test_runsub ./comsub25.sub test_runsub ./comsub26.sub +test_runsub ./comsub27.sub diff --git a/tests/comsub27.sub b/tests/comsub27.sub new file mode 100644 index 00000000..eddcb96f --- /dev/null +++ b/tests/comsub27.sub @@ -0,0 +1,73 @@ +declare -i x +x='a[${ unset x;}]' +declare -p x +unset x + +declare -a a +x=a[${ unset x;}] +declare -p x +unset x + +x=a[${ unset x;}] +declare -p x +unset x + +x=${ unset x; } +declare -p x +unset x + +declare -a x +x[0]=abc +x=${ unset x; } +declare -p x +unset x + +declare -i x +x='a[${ unset x;}]' printenv x +declare -p x +unset x + +declare -i x +x=${ unset x;} +declare -p x +unset x + +declare -i x +x='${ unset x;}' +declare -p x +unset x + +( SECONDS=${ unset SECONDS; } +declare -p SECONDS +unset SECONDS ) + +( SECONDS='${ unset SECONDS; }' +declare -p SECONDS ) + +declare -i x='a[${ unset x; }]' +declare -p x +unset x + +declare -ia x=(3 5 7 9) +declare -n foo='x[2]' +foo=a[${ unset x; }] +declare -p x +unset x + +declare -ai a=(1 'b[${ unset a; }]' 3) +declare -p a +unset a + +declare -ai a=(1 "b[${ unset a; }]" 3) +declare -p a +unset a + +# uses kvpair-style +declare -Ai a=(1 'b[${ unset a; }]' 3) +declare -p a +unset a + +# uses kvpair-style +declare -Ai a=(1 "b[${ unset a; }]" 3) +declare -p a +unset a diff --git a/tests/errors.right b/tests/errors.right index ac56c508..e7fd363c 100644 --- a/tests/errors.right +++ b/tests/errors.right @@ -100,45 +100,47 @@ read: usage: read [-Eers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars ./errors.tests: line 265: VAR: readonly variable ./errors.tests: line 268: read: XX: invalid file descriptor specification ./errors.tests: line 269: read: 42: invalid file descriptor: Bad file descriptor -./errors.tests: line 272: mapfile: XX: invalid file descriptor specification -./errors.tests: line 273: mapfile: 42: invalid file descriptor: Bad file descriptor -./errors.tests: line 277: mapfile: empty array variable name -./errors.tests: line 278: mapfile: `invalid-var': not a valid identifier -./errors.tests: line 281: readonly: -x: invalid option +./errors.tests: line 270: read: 0: read error: Bad file descriptor +2 +./errors.tests: line 273: mapfile: XX: invalid file descriptor specification +./errors.tests: line 274: mapfile: 42: invalid file descriptor: Bad file descriptor +./errors.tests: line 278: mapfile: empty array variable name +./errors.tests: line 279: mapfile: `invalid-var': not a valid identifier +./errors.tests: line 282: readonly: -x: invalid option readonly: usage: readonly [-aAf] [name[=value] ...] or readonly -p -./errors.tests: line 284: eval: -i: invalid option +./errors.tests: line 285: eval: -i: invalid option eval: usage: eval [arg ...] -./errors.tests: line 285: command: -i: invalid option +./errors.tests: line 286: command: -i: invalid option command: usage: command [-pVv] command [arg ...] -./errors.tests: line 288: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") ./errors.tests: line 289: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 292: trap: NOSIG: invalid signal specification -./errors.tests: line 295: trap: -s: invalid option +./errors.tests: line 290: /bin/sh + 0: arithmetic syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: line 293: trap: NOSIG: invalid signal specification +./errors.tests: line 296: trap: -s: invalid option trap: usage: trap [-Plp] [[action] signal_spec ...] -./errors.tests: line 301: return: can only `return' from a function or sourced script -./errors.tests: line 305: break: 0: loop count out of range -./errors.tests: line 309: continue: 0: loop count out of range -./errors.tests: line 314: builtin: -x: invalid option +./errors.tests: line 302: return: can only `return' from a function or sourced script +./errors.tests: line 306: break: 0: loop count out of range +./errors.tests: line 310: continue: 0: loop count out of range +./errors.tests: line 315: builtin: -x: invalid option builtin: usage: builtin [shell-builtin [arg ...]] -./errors.tests: line 317: builtin: bash: not a shell builtin -./errors.tests: line 321: bg: no job control -./errors.tests: line 322: fg: no job control +./errors.tests: line 318: builtin: bash: not a shell builtin +./errors.tests: line 322: bg: no job control +./errors.tests: line 323: fg: no job control kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec] -./errors.tests: line 326: kill: -s: option requires an argument -./errors.tests: line 328: kill: S: invalid signal specification -./errors.tests: line 330: kill: `': not a pid or valid job spec +./errors.tests: line 327: kill: -s: option requires an argument +./errors.tests: line 329: kill: S: invalid signal specification +./errors.tests: line 331: kill: `': not a pid or valid job spec kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec] -./errors.tests: line 334: kill: SIGBAD: invalid signal specification -./errors.tests: line 336: kill: BAD: invalid signal specification -./errors.tests: line 338: kill: `@12': not a pid or valid job spec -./errors.tests: line 341: unset: BASH_LINENO: cannot unset -./errors.tests: line 341: unset: BASH_SOURCE: cannot unset -./errors.tests: line 344: set: trackall: invalid option name -./errors.tests: line 345: set: -q: invalid option +./errors.tests: line 335: kill: SIGBAD: invalid signal specification +./errors.tests: line 337: kill: BAD: invalid signal specification +./errors.tests: line 339: kill: `@12': not a pid or valid job spec +./errors.tests: line 342: unset: BASH_LINENO: cannot unset +./errors.tests: line 342: unset: BASH_SOURCE: cannot unset +./errors.tests: line 345: set: trackall: invalid option name +./errors.tests: line 346: set: -q: invalid option set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] -./errors.tests: line 346: set: -i: invalid option +./errors.tests: line 347: set: -i: invalid option set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] -./errors.tests: line 350: xx: readonly variable +./errors.tests: line 351: xx: readonly variable 1 errors1.sub ./errors1.sub: line 14: .: -i: invalid option diff --git a/tests/errors.tests b/tests/errors.tests index 45d6994e..822feb0d 100644 --- a/tests/errors.tests +++ b/tests/errors.tests @@ -267,6 +267,7 @@ read VAR < /dev/null # invalid file descriptor read -u XX < /dev/null read -u 42 < /dev/null +read var <&- ; echo $? # same with mapfile mapfile -u XX A < /dev/null diff --git a/tests/intl.right b/tests/intl.right index 4943cb31..4d927d66 100644 --- a/tests/intl.right +++ b/tests/intl.right @@ -25,7 +25,7 @@ bytematch 0000000 254 012 0000002 unicode1.sub -Passed all 1770 Unicode tests +Failed 0 Unicode tests unicode2.sub 0000000 303 277 012 0000003 diff --git a/tests/parser.right b/tests/parser.right index 673c55ce..16a39459 100644 --- a/tests/parser.right +++ b/tests/parser.right @@ -20,3 +20,5 @@ ok 1 x x x +./posix2syntax.sub: line 103: syntax error near unexpected token `!' +./posix2syntax.sub: line 103: `( : | ! : | false )' diff --git a/tests/posix2syntax.sub b/tests/posix2syntax.sub index e2c2368f..a97371a0 100644 --- a/tests/posix2syntax.sub +++ b/tests/posix2syntax.sub @@ -99,3 +99,5 @@ echo $x done esac +# some shells accept this, but posix does not allow it +( : | ! : | false ) diff --git a/tests/run-all b/tests/run-all index 206e6928..cf795478 100644 --- a/tests/run-all +++ b/tests/run-all @@ -62,9 +62,13 @@ echo Any output from any test, unless otherwise noted, indicates a possible anom # keep track of passed and failed tests and report them if [ -t 1 ]; then - # can't rely on having $'...' or printf understanding \e - # bright red background, white foreground text - CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + if type -P tput >/dev/null; then + CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) + else + # can't rely on having $'...' or printf understanding \e + # bright red background, white foreground text + CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m') + fi else CSTART= CEND= fi diff --git a/tests/unicode1.sub b/tests/unicode1.sub index feb79d01..91b01040 100644 --- a/tests/unicode1.sub +++ b/tests/unicode1.sub @@ -105,7 +105,6 @@ if [ -n "$FR_LOCALE" ]; then TestCodePage ${FR_LOCALE} fr_FR_ISO_8859_1 else localewarn fr_FR.ISO8859-1 - fi zh_TW_BIG5=( @@ -604,8 +603,9 @@ C_UTF_8=( ) TestCodePage en_US.UTF-8 C_UTF_8 +echo "Failed ${ErrorCnt} Unicode tests" if [ ${ErrorCnt} -gt 0 ]; then - echo "Failed ${ErrorCnt} of ${TestCnt} Unicode tests" -else - echo "Passed all ${TestCnt} Unicode tests" + echo "Passed $(( ${TestCnt} - ${ErrorCnt} )) of ${TestCnt} Unicode tests" fi + +exit ${ErrorCnt} diff --git a/variables.c b/variables.c index 2d23a0f2..59423372 100644 --- a/variables.c +++ b/variables.c @@ -2849,6 +2849,8 @@ make_local_array_variable (const char *name, int flags) var_setarray (var, array); } + INVALIDATE_EXPORTSTR (var); + /*itrace("make_local_array_variable: unsetting att_tempvar");*/ VUNSETATTR (var, att_tempvar); @@ -2912,6 +2914,8 @@ make_local_assoc_variable (const char *name, int flags) var_setassoc (var, hash); } + INVALIDATE_EXPORTSTR (var); + /*itrace("make_local_assoc_variable: unsetting att_tempvar");*/ VUNSETATTR (var, att_tempvar);