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

This commit is contained in:
Chet Ramey
2025-11-11 11:36:53 -05:00
parent c299f535be
commit 81d8584268
22 changed files with 237 additions and 54 deletions
+47
View File
@@ -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 <g.branden.robinson@gmail.com>
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 <grishalevit@gmail.com>
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 <grishalevit@gmail.com>
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 <grishalevit@gmail.com>
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 <kfm@plushkava.net>
builtins/read.def
- read_builtin: POSIX says read must return >1 on a read error, 1
is reserved for EOF
+1
View File
@@ -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
+1 -1
View File
@@ -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)
+2 -1
View File
@@ -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"
+5 -3
View File
@@ -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;
+2 -2
View File
@@ -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))
+4
View File
@@ -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;
+7
View File
@@ -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);
}
+1 -1
View File
@@ -1,3 +1,3 @@
Type `sh run-all'.
Run `make tests' from the bash build directory.
Read COPYRIGHT for copyright information.
+9 -5
View File
@@ -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} "$@"
+9 -4
View File
@@ -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} "$@"
+23
View File
@@ -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" )
+1
View File
@@ -152,3 +152,4 @@ test_runsub ./comsub23.sub
test_runsub ./comsub24.sub
test_runsub ./comsub25.sub
test_runsub ./comsub26.sub
test_runsub ./comsub27.sub
+73
View File
@@ -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
+31 -29
View File
@@ -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
+1
View File
@@ -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
+1 -1
View File
@@ -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
+2
View File
@@ -20,3 +20,5 @@ ok 1
x
x
x
./posix2syntax.sub: line 103: syntax error near unexpected token `!'
./posix2syntax.sub: line 103: `( : | ! : | false )'
+2
View File
@@ -99,3 +99,5 @@ echo $x
done
esac
# some shells accept this, but posix does not allow it
( : | ! : | false )
+7 -3
View File
@@ -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
+4 -4
View File
@@ -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}
+4
View File
@@ -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);