[Bash-completion-devel] [bash-completion-Bugs][312741] shopt -s failglob breaks __reassemble_comp_words_by_ref

bash-completion-bugs at alioth.debian.org bash-completion-bugs at alioth.debian.org
Mon Feb 17 13:03:42 UTC 2014


bash-completion-Bugs item #312741 was changed at 17/02/2014 14:03 by Dams Nadé
You can respond by visiting: 
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=312741&group_id=100114

Status: Open
Priority: 3
Submitted By: Ville Skyttä  (scop-guest)
Assigned to: Nobody (None)
Summary: shopt -s failglob breaks __reassemble_comp_words_by_ref 
Distribution: None
Originally reported in: None
Milestone: None
Status: None
Original bug number: 


Initial Comment:
$ shopt -s failglob
$ ssh <TAB>bash: no match: words[0]=${!ref}${COMP_WORDS[i]}

http://thread.gmane.org/gmane.comp.shells.bash.completion.devel/2546

----------------------------------------------------------------------

Comment By: Dams Nadé (anvil-guest)
Date: 17/02/2014 14:03

Message:
I got this patch, here to solve this issue i think :

diff -u --exclude CVS --exclude .svn --exclude .bzr --exclude .pc --exclude test --exclude completions --exclude debian -ub bash-completion-1.3.orig/bash_completion bash-completion-1.3/bash_completion
--- bash-completion-1.3.orig/bash_completion    2013-09-12 16:06:45.000000000 +0200
+++ bash-completion-1.3/bash_completion 2013-09-12 17:25:19.000000000 +0200
@@ -286,7 +286,7 @@
     fi
         
     # Default to cword unchanged
-    eval $3=$COMP_CWORD
+    printf -v "$3" %s "$COMP_CWORD"
     # Are characters excluded which were former included?
     if [[ $exclude ]]; then
         # Yes, list of word completion separators has shrunk;
@@ -296,26 +296,28 @@
             # empty and is word made up of just word separator characters to be
             # excluded?
             while [[ $i -gt 0 && ${COMP_WORDS[$i]} && 
-                ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]} 
+                ${COMP_WORDS[$i]//[^$exclude]} = ${COMP_WORDS[$i]} 
             ]]; do
                 [ $j -ge 2 ] && ((j--))
                 # Append word separator to current word
                 ref="$2[$j]"
-                eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
+                printf -v "$ref" %s "${!ref}${COMP_WORDS[i]}"
                 # Indicate new cword
-                [ $i = $COMP_CWORD ] && eval $3=$j
+                [ $i = $COMP_CWORD ] && printf -v "$3" %s "$j"
                 # Indicate next word if available, else end *both* while and for loop
                 (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2
             done
             # Append word to current word
             ref="$2[$j]"
-            eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
+            printf -v "$ref" %s "${!ref}${COMP_WORDS[i]}"
             # Indicate new cword
-            [[ $i == $COMP_CWORD ]] && eval $3=$j
+            [[ $i == $COMP_CWORD ]] && printf -v "$3" %s "$j"
         done
     else
         # No, list of word completions separators hasn't changed;
-        eval $2=\( \"\${COMP_WORDS[@]}\" \)
+        for i in "${!COMP_WORDS[@]}"; do
+            printf -v "$2[i]" %s "${COMP_WORDS[i]}"
+        done
     fi
 } # __reassemble_comp_words_by_ref()
 
@@ -1481,7 +1483,7 @@
         COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]}
     done
     for (( i; i <= COMP_CWORD; i++ )); do
-        unset COMP_WORDS[i];
+        unset 'COMP_WORDS[i]'
     done
     COMP_CWORD=$(( $COMP_CWORD - $word_offset ))
 


----------------------------------------------------------------------

Comment By: Dams Nadé (anvil-guest)
Date: 17/02/2014 13:49

Message:
A better eval-free approach would be to simple do

printf -v "$2" %s "${!ref}${COMP_WORDS[i]}"

It's faster and more secure this way, imho.

----------------------------------------------------------------------

Comment By: Ville Skyttä  (scop-guest)
Date: 17/02/2014 13:45

Message:
Unfortunately __reassemble_comp_words_by_ref is not the only thing affected by failglob. At least all _install_xspec ones and ipmitool are, and I don't know of a good recipe how to detect/grep an exhaustive list.

One approach for better-than-nothing coverage is to set "shopt -s failglob" in our test suite's test/config/bashrc and start working on the failures it causes there.

----------------------------------------------------------------------

Comment By: Isaac Jurado (etanol-guest)
Date: 17/02/2014 11:57

Message:
I found this issue too (using 2.0 from Ubuntu Saucy).  There is actually a very simple fix that allows you to have failglob enabled with bash_completion included too.

The trick is to temporarily disable failglob while executing the __reassemble_comp_words_by_ref and then restoring it, in case it was disabled:


--- /usr/share/bash-completion/bash_completion.orig	2014-02-17 11:44:05.879501602 +0100
+++ /usr/share/bash-completion/bash_completion	2014-02-17 11:42:25.967499666 +0100
@@ -237,7 +237,10 @@
 #
 __reassemble_comp_words_by_ref()
 {
-    local exclude i j line ref
+    local exclude i j line ref fgr
+    shopt -pq failglob
+    fgr=$?
+    shopt -u failglob
     # Exclude word separator characters?
     if [[ $1 ]]; then
         # Yes, exclude word separator characters;
@@ -288,6 +291,7 @@
         # No, list of word completions separators hasn't changed;
         eval $2=\( \"\${COMP_WORDS[@]}\" \)
     fi
+    (( $fgr )) || shopt -s failglob
 } # __reassemble_comp_words_by_ref()
 



----------------------------------------------------------------------

Comment By: Ian! D. Allen (idallen-guest)
Date: 31/08/2013 00:28

Message:
In addition to failures under "set -u", using "shopt -s failglob" also
causes errors that make all bash_completion versions (including 2.1)
unusable:

$ env -i bash --login --noprofile --norc
bash-4.2$ shopt -s failglob
bash-4.2$ . /usr/share/bash-completion/bash_completion
bash-4.2$ make <TAB> bash: no match: words[0]=${!ref}${COMP_WORDS[i]}
bash-4.2$ find <TAB> bash: no match: words[0]=${!ref}${COMP_WORDS[i]}
bash-4.2$ mutt <TAB> bash: no match: words[0]=${!ref}${COMP_WORDS[i]}
bash-4.2$ date <TAB> bash: no match: words[0]=${!ref}${COMP_WORDS[i]}
bash-4.2$ echo <TAB> bash: no match: words[0]=${!ref}${COMP_WORDS[i]}
etc.

The code has many errors where characters are not quoted (e.g. bash
array subscripts), so they try to expand as GLOB file names and fail.

As an example, to fix the above, change the lines:

eval $2[$j]=\${!ref}\${COMP_WORDS[i]}

to this:

eval "$ref"='${!ref-}${COMP_WORDS[i]-}'

everywhere (and also fix it so that "set -u" doesn't also make it fail).

----------------------------------------------------------------------

You can respond by visiting: 
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=312741&group_id=100114



More information about the Bash-completion-devel mailing list