Bash parameter transforamtion on empty array triggers unset variable.

2020-08-10 Thread Andrew Neff
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-musl
Compiler: gcc
Compilation CFLAGS: -g -O2 -Wno-parentheses -Wno-format-security
uname output: Linux 28e237a5e16f 5.5.7-200.fc31.x86_64 #1 SMP Fri Feb 28
17:18:37 UTC 2020 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-musl

Bash Version: 5.1
Patch Level: 0
Release Status: alpha

Description:
I do not know if this is related to bash 5.1 erroneously being
"a little aggressive about skipping over empty strings" mentioned
in "Declaring arrays with empty string in one line is bugged", but using
parameter transformation on an empty array, throws an error if "set -u" is
turned on. This was not how bash 4.4 and 5.0 worked. This bug makes it
impossible to check if an empty variable is an array using parameter
transformation while "set -u" is turned on

Repeat-By:
# Indirection
docker run -it --rm bash:5.1-alpha bash -uc 'foo(){ echo "${!1@a}";
}; bar=(); foo bar'
# Empty array
docker run -it --rm bash:5.1-alpha bash -uc 'bar=(); echo "${bar@a}"'

# Declared unset array
docker run -it --rm bash:5.1-alpha bash -uc 'declare -a bar; echo
"${bar@a}"'
# Empty associative array
docker run -it --rm bash:5.1-alpha bash -uc 'declare -A Bar=();
echo "${Bar@a}"'
# Declared unset associative array
docker run -it --rm bash:5.1-alpha bash -uc 'declare -A Bar; echo
"${Bar@a}"'

# I also tested on bash:devel-20200805, with the same results

Fix:
# All five of the above examples work in bash 4.4 and 5.0, and I
would expect the same behavior in bash 5.1
# Expected behavior that is already there in 5.1 alpha
docker run -it --rm bash:5.1-alpha bash -uc 'bar=(); echo
"${bar[@]}' # succeeds, but this is already consistent with bash 4.4 and
5.0. So this is expected to succeed.
docker run -it --rm bash:5.1-alpha bash -uc 'bar=(); echo
"${bar[@]+set}' # echos nothing, but this is already consistent with bash
3.2 and 5.0. So this is expected behavior
docker run -it --rm bash:5.1-alpha bash -uc 'bar=(); echo "${bar}'
# fails, but this is already consistent with bash 4.4 and 5.0. So this is
expected to fail, there is no 0th element to the array.
docker run -it --rm bash:5.1-alpha bash -uc 'bar=(); echo
"${bar+set}' # echos nothing, but this is already consistent with bash 3.2
and 5.0. So this is expected behavior

Thanks


Re: Bash parameter transforamtion on empty array triggers unset variable.

2020-08-11 Thread Andrew Neff
Ah, I see the confusion.

The issue you pointed out, "@Q breaks set -o nounset" refers to quote
parameter expansion, as does the line in CHANGES-5.1, 1.q, which makes
sense to call this a bug that was allowed in bash 4.4 and 5.0.

I should have specified, the focus of this issue is the "@a" expansion. It
makes sense that @Q/E/P/A expansion should not work on unset variables with
nounset enabled. However, @a is uniquely different, in that it does not
have to do with the value of the variable, but rather the variable type. My
"set -eu" compatible library uses the @a expansion (for bash 4.4 and newer)
because it had previously worked on unset values with set -u enabled, which
was a very useful feature.

Here are 3 specific details I would like to address:

1. @a expansion should work on unset variables with "set -u" in bash 5.1.
It seems like the correct thing to do. Only @a expansion. This has been a
very useful feature in bash 4.4 and 5.0.
Should fail: (set -eu; declare -a x; echo "${x@Q}")
Should not fail:  (set -eu; declare -a x; echo "${x@a}")

2. With "set -u", the following works in bash 4.4 or newer (and makes sense
that it works): (set -eu; x=(); echo "${x[@]}")
Here x is not unset, it is set to an empty array. This expansion make sense
with nounset turned on because x is not unset, it is set to ()
However, this fails: (set -eu; x=(); echo "${x@a}")
This is an inconsistent behavior, and it seems to me the ${x@a} should
definitely work here, with nounset turns on

3. The same as #2, but for associative arrays
Works: (set -eu; declare -A x=(); echo "${x[@]}")
Does not work, but should: (set -eu; declare -A x=(); echo "${x@a}")

Thanks


On Tue, Aug 11, 2020 at 9:51 AM Chet Ramey  wrote:

> On 8/10/20 5:52 PM, Andrew Neff wrote:
>
> > Bash Version: 5.1
> > Patch Level: 0
> > Release Status: alpha
> >
> > Description:
> > I do not know if this is related to bash 5.1 erroneously being
> > "a little aggressive about skipping over empty strings" mentioned
> > in "Declaring arrays with empty string in one line is bugged", but using
> > parameter transformation on an empty array, throws an error if "set -u"
> is
> > turned on. This was not how bash 4.4 and 5.0 worked. This bug makes it
> > impossible to check if an empty variable is an array using parameter
> > transformation while "set -u" is turned on
>
> This was a bug in bash-5.0 (and 4.4) and was fixed in early March 2019 as
> the result of
>
> https://lists.gnu.org/archive/html/bug-bash/2019-03/msg00010.html
>
> It's in CHANGES.
>
> There are some other changes in how bash displays attributes of unset
> variables when `nounset' is not enabled, but unset variables used in word
> expansions should trigger an error -- with the usual @/* exceptions -- when
> set -u is enabled.
>
> --
> ``The lyf so short, the craft so long to lerne.'' - Chaucer
>  ``Ars longa, vita brevis'' - Hippocrates
> Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
>


caller returns wrong line number in command substitution

2022-10-18 Thread Andrew Neff via Bug reports for the GNU Bourne Again SHell
Machine: x86_64
OS: linux-musl
Compiler: gcc
Compilation CFLAGS: -g -O2
uname output: Linux cfa1574b05c7 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed 
Mar 2 00:30:59 UTC 2022 x86_64 GNU/Linux
uname output: Linux 3beae0f31cdf 5.18.18-100.fc35.x86_64 #1 SMP PREEMPT_DYNAMIC 
Wed Aug 17 16:09:22 UTC 2022 x86_64 Linux
Machine Type: x86_64-pc-linux-musl
Docker: docker run -it --rm bash:5.2

Description:
  Using the "caller" command on a line of bash code in a process substitution 
has been incorrect from bash 3.2 through 5.1, but I could write my code in such 
a way to work around it. Some of these workarounds no longer function in bash 
5.2. I saw that you made some changes to this code [see below], however, I 
think they introduced another regression to how caller calculates the line 
offset. In the following tests, caller should always return the last line in a 
multi-line bash call, but that is not the case now in a process substitution in 
bash 5.2 (test 5)

  [quote]
c. Rewrote the command substitution parsing code to call the parser 
recursively and rebuild the command string from the parsed command. This allows 
better syntax checking and catches errors much earlier. Along with this, if 
command substitution parsing completes with here-documents remaining to be 
read, the shell prints a warning message and reads the here-document bodies 
from the current input stream

Repeat-By:
  Here's a small script to repeat the problem:

#!/usr/bin/env bash
function foobar()
{
  caller >&2
}
foobar "test0
...
bar"
true <(foobar "test1
...
bar")
true <(
  foobar "test2
...
bar")
true <(\
  foobar "test3
...
bar")
read -rd '' foo < <(foobar "test4
...
bar") || :
read -rd '' foo < <(
  foobar "test5
...
bar") || :
read -rd '' foo < <(\
  foobar "test6
...
bar")
read -rd '' foo < \
<(foobar "test7
...
bar")
  Results:

  Test Ans 5.1 5.2
  08   8   8
  111  13  13
  215  18  17
  319  21  21
  422  22  22
  526  26  25
  630  29  29
  734  33  33

  Summary:
  Test 0: no command substitution, it works.
  Test 1: the answer is off by the number of lines. So 1 line is right, 2 lines 
if off by one line, 3 lines (as show) is off by 2. If it was 10 lines, the 
answer would be off by 9.
  Test 2: Same offset as Test 1. On bash 3.2-5.1 off by one additional line
  Test 3: Same as test 1
  Test 4: Actually right
  Test 5: Off by -1 lines in bash 5.2, right on bash 3.2-5.1
  Test 6: Always off by -1 lines
  Test 7: Same as Test 6

Fix/Workarounds:
  Only the Test0 and Test4 consistently give the right answer. However for 
readability and other reasons, I don't always want those syntaxes.


Re: caller returns wrong line number in command substitution

2022-10-18 Thread Andrew Neff via Bug reports for the GNU Bourne Again SHell
Oops, my mistake. Got some terms mixed up a little there.

Yes, every time I command substitution, I meant process substitution. So that 
release note for "Rewrote the command substitution" most likely nothing to do 
with this.

From: Robert Elz 
Sent: Tuesday, October 18, 2022 7:09 PM
To: Andrew Neff 
Cc: bug-bash@gnu.org 
Subject: Re: caller returns wrong line number in command substitution

There are no command substitutions in any of your examples.
A command substitution is what you get with $( )  (or if you
really like obsolete syntax for some reason, ``).

What you're showing is process substitution.

This has nothing to do with whether or not there is an issue
here that's worth fixing however - but bash's management of
line numbers has always been "close enough" rather than "accurate".

kre



Exit trap changes return value of subshell for uncaught trap signals

2022-10-19 Thread Andrew Neff via Bug reports for the GNU Bourne Again SHell
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -O2 -flto=auto -ffat-lto-objects -fexceptions -g 
-grecord-gcc-switches -pipe -Wall -Werror=format-security 
-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS 
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong 
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic 
-fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection
uname output: Linux 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 
00:30:59 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
uname output: Linux 17d50c74abf4 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed 
Mar 2 00:30:59 UTC 2022 x86_64 GNU/Linux
Machine Type: x86_64-redhat-linux-gnu
Environment Bugged: docker run -it --rm bash:5.1
Environment Working: docker run -it --rm bash:5.0

Bash Version: 5.1
Patch Level: 12
Release Status: release

Description:
I discovered an inconsistent bug starting in bash 5.1.12. Setting the 
EXIT trap in the grandparent of a subshell that exits via an unset trap signal 
causes different return values. If the EXIT trap is unset, the subshell returns 
128+signal number (e.g. 138 , for SIGUSR1 (10)). However when the EXIT trap is 
set in the grandparent, the subshell returns 0 instead.

Repeat-By:
Run this code in bash 5.1.12 or newer. You’ll see “Error: 138” both 
before and after the EXIT signal is set on the older bashes, but not on 5.1.12 
or newer.

#!/usr/bin/env bash
set -eu
child_signal()
(
  trap "echo you will not see this" USR1
  (
kill -USR1 "${BASHPID}"
# echo "Uncomment this to mysteriously fix"
  ) || echo "Error: ${rv=${?}}"
  [ "${rv-0}" != "0" ]
  echo
)
echo "No exit trap"
child_signal
echo "Exit trap set"
trap 'echo atexiting...' EXIT
child_signal
echo "The end"

Observed Erroneous Result:
No exit trap
User defined signal 1
Error: 138

Exit trap set
atexiting...

Expected Result (e.g., as in 5.1.11):
No exit trap
User defined signal 1
Error: 138

Exit trap set
User defined signal 1
Error: 138

The end
atexiting...

Fix:
The bug started in the 5.1.12 patch, and it does not happen in 5.1.11. 
The bug was still present in the 2022-10-15 devel branch. I am only able to 
manifest it with the EXIT signal. I could not reproduce it with other signals 
(e.g. “set -T” + the RETURN signal)
One workaround: uncomment the “Uncomment this to mysteriously fix” line 
and the bug disappears.