Bug 1875566

Summary: Bash says a declared but empty array is unbound
Product: Red Hat Enterprise Linux 8 Reporter: Miciah Dashiel Butler Masters <mmasters>
Component: bashAssignee: Siteshwar Vashisht <svashisht>
Status: CLOSED WONTFIX QA Contact: Karel Volný <kvolny>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 8.2CC: amcdermo
Target Milestone: rc   
Target Release: 8.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2021-10-12 07:30:58 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Miciah Dashiel Butler Masters 2020-09-03 19:06:56 UTC
Description of problem:

In bash-4.2.46-31.el7.x86_64 from Red Hat Enterprise Linux Workstation release 7.6, a declared but empty array is considered bound but empty:

    % bash -c 'set -u; declare -a ary; echo "${#ary[@]}"'
    0
    % bash -c 'set -u; declare -A ary; echo "${#ary[@]}"'
    0

In bash-4.4.19-10.el8.x86_64 from Red Hat Enterprise Linux release 8.2, a declared but empty array is considered unbound:

    # bash -c 'set -u; declare -a ary; echo "${#ary[@]}"'
    bash: ary: unbound variable
    # bash -c 'set -u; declare -A ary; echo "${#ary[@]}"'
    bash: ary: unbound variable


Version-Release number of selected component (if applicable):

bash-4.4.19-10.el8.x86_64


How reproducible:

100%


Steps to Reproduce:

1. Run the following command in Bash:

       set -u; declare -a ary; echo "${#ary[@]}"

2. Run the following command in Bash:

       set -u; declare -A ary; echo "${#ary[@]}"


Actual results:

After each step, Bash prints the following error message and exits:

    ary: unbound variable


Expected results:

After each step, Bash should print "0" without exiting.


Additional info:

I bisected the change in behavior to <http://git.savannah.gnu.org/cgit/bash.git/commit/?id=ac50fbac377e32b98d2de396f016ea81e8ee9961>.  

If I check out commit ac50fbac377e32b98d2de396f016ea81e8ee9961, apply the following patch, and rebuild, I see the old behavior:

    diff --git a/builtins/declare.def b/builtins/declare.def
    index a634e7ce..af38f085 100644
    --- a/builtins/declare.def
    +++ b/builtins/declare.def
    @@ -483,14 +483,10 @@ declare_internal (list, local_var)
                  if (flags_on & att_assoc)
                    {
                      var = make_new_assoc_variable (name);
    -                 if (offset == 0)
    -                   VSETATTR (var, att_invisible);
                    }
                  else if ((flags_on & att_array) || making_array_special)
                    {
                      var = make_new_array_variable (name);
    -                 if (offset == 0)
    -                   VSETATTR (var, att_invisible);
                    }
                  else
     #endif

Based on this finding, I believe the following entry from the changelog is relevant:

    builtins/declare.def
    	- declare_internal: if an array variable is declared using `declare -a'
    	  or `declare -A', but not assigned a value, set the `invisible'
    	  attribute so the variable does not show up as set.  Fix for bug
    	  about variable initialization reported by Tim Friske <me>

From the changelog entry, it this seems to be an intentional change in semantics.  However, it is a compatibility-breaking change; that is, scripts that previously worked now break (for example, see https://github.com/openshift/cluster-dns-operator/pull/192).  

I did not find any mention of this change in semantics in the release notes at <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/8.0_release_notes/index>, <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/8.1_release_notes/index>, or <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/8.2_release_notes/index>.