* [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS @ 2017-02-16 23:05 Martijn Dekker 2017-02-17 0:07 ` Martijn Dekker 2017-02-17 5:14 ` Bart Schaefer 0 siblings, 2 replies; 6+ messages in thread From: Martijn Dekker @ 2017-02-16 23:05 UTC (permalink / raw) To: Zsh hackers list In SHWORDSPLIT mode, if IFS is null (no field splitting) or unset (default fieldsplitting), both var=$* and var=$@ act like var=("$@"), so turn 'var' into an array. In native mode, zsh acts correctly (POSIXly), i.e.: all the parameters get concatenated with no separator, since IFS is null. So this should be fixed for sh mode. Note that var="$@" and var="$*" act correctly in any mode. So, to trigger the bug: - the quotes must be absent - IFS must be null (i.e. set and empty) or unset - SHWORDSPLIT must be on Here's a little test script. #! Src/zsh -f set -- * for ifs in default null unset; do for wordsplit in native sh; do print -r -- "--- $ifs IFS, $wordsplit splitting ---" case $ifs in default) IFS=$' \t\n\00' ;; null) IFS= ;; unset) unset -v IFS ;; esac case $wordsplit in native) unsetopt shwordsplit ;; sh) setopt shwordsplit ;; esac for testcmd in 'var=$@' 'var=$*' 'var="$@"' 'var="$*"'; do (set -x; eval "$testcmd") done done done You see the bug happen under "--- null IFS, sh splitting ---" and "--- unset IFS, sh splitting ---": --- null IFS, sh splitting --- +test.zsh:19> eval 'var=$@' +(eval):1> var=( Config Doc Etc Makefile Src Test config.cache config.h config.log config.modules config.modules.sh config.status stamp-h test.zsh ) +test.zsh:19> eval 'var=$*' +(eval):1> var=( Config Doc Etc Makefile Src Test config.cache config.h config.log config.modules config.modules.sh config.status stamp-h test.zsh ) [...] --- unset IFS, sh splitting --- +test.zsh:19> eval 'var=$@' +(eval):1> var=( Config Doc Etc Makefile Src Test config.cache config.h config.log config.modules config.modules.sh config.status stamp-h test.zsh ) +test.zsh:19> eval 'var=$*' +(eval):1> var=( Config Doc Etc Makefile Src Test config.cache config.h config.log config.modules config.modules.sh config.status stamp-h test.zsh ) Thanks, - M. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS 2017-02-16 23:05 [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS Martijn Dekker @ 2017-02-17 0:07 ` Martijn Dekker 2017-02-17 5:14 ` Bart Schaefer 1 sibling, 0 replies; 6+ messages in thread From: Martijn Dekker @ 2017-02-17 0:07 UTC (permalink / raw) To: Zsh hackers list Op 17-02-17 om 00:05 schreef Martijn Dekker: > Here's a little test script. Figured I might as well save you some work and turn it into a proper zsh test case instead. diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 9128c3c..ca1dcc2 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -2056,3 +2056,81 @@ 0:Regression: "-" became Dash in workers/37689, breaking ~- expansion *>* F:We do not care what $OLDPWD is, as long as it doesn't cause an error + + ( + set -- one 'two three' four + for ifs in default null unset; do + for wordsplit in native sh; do + print -r -- "--- $ifs IFS, $wordsplit splitting ---" + case $ifs in + default) IFS=$' \t\n\00' ;; + null) IFS= ;; + unset) unset -v IFS ;; + esac + case $wordsplit in + native) unsetopt shwordsplit ;; + sh) setopt shwordsplit ;; + esac + for testcmd in 'var=$@' 'var=$*' 'var="$@"' 'var="$*"'; do + print -r -- "> $testcmd" + eval "$testcmd" + printf '[%s]\n' "${var[@]}" + done + done + done + ) +0:Assigning $@, $*, "$@", "$*" to var with various shwordsplit/IFS settings +>--- default IFS, native splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- default IFS, sh splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- null IFS, native splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[onetwo threefour] +>> var="$@" +>[one two three four] +>> var="$*" +>[onetwo threefour] +>--- null IFS, sh splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[onetwo threefour] +>> var="$@" +>[one two three four] +>> var="$*" +>[onetwo threefour] +>--- unset IFS, native splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- unset IFS, sh splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS 2017-02-16 23:05 [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS Martijn Dekker 2017-02-17 0:07 ` Martijn Dekker @ 2017-02-17 5:14 ` Bart Schaefer 2017-02-20 18:58 ` Bart Schaefer 1 sibling, 1 reply; 6+ messages in thread From: Bart Schaefer @ 2017-02-17 5:14 UTC (permalink / raw) To: Martijn Dekker, Zsh hackers list On Feb 17, 12:05am, Martijn Dekker wrote: } } In SHWORDSPLIT mode, if IFS is null (no field splitting) or unset } (default fieldsplitting), both var=$* and var=$@ act like var=("$@"), so } turn 'var' into an array. This sounded naggingly familiar, and indeed: 30299: "$*" was split with SHWORDSPLIT if IFS was empty or unset Undoing 30299 fixes the bug Martijn is reporting here, but re-introduces the incorrect splitting behavior. I haven't gotten any further with it than that. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS 2017-02-17 5:14 ` Bart Schaefer @ 2017-02-20 18:58 ` Bart Schaefer 2017-02-20 21:20 ` Bart Schaefer 0 siblings, 1 reply; 6+ messages in thread From: Bart Schaefer @ 2017-02-20 18:58 UTC (permalink / raw) To: Zsh hackers list On Feb 16, 9:14pm, Bart Schaefer wrote: } } } In SHWORDSPLIT mode, if IFS is null (no field splitting) or unset } } (default fieldsplitting), both var=$* and var=$@ act like var=("$@"), so } } turn 'var' into an array. } } Undoing 30299 fixes the bug Martijn is reporting here, but re-introduces } the incorrect splitting behavior. I have a question about one of your test cases. >--- null IFS, native splitting --- >> var=$@ >[one two three four] >> var=$* >[onetwo threefour] >> var="$@" >[one two three four] >> var="$*" >[onetwo threefour] Joining the array for assignment is forced by prefork() passing PREFORK_SINGLE down to paramsubst(). Joining is supposed to be done on the first character of $IFS in this case. When IFS is null (as opposed to unset), this causes both $@ and $* to join on empty string. Where is the space supposed to come from when joining $@ here? As for the reported bug -- in certain circumstances paramsubst() skips doing joins/splits to avoid other problems with the semantics, which results in an array being returned to prefork() even though it asked for a scalar. Instead of choking on this, prefork() converts to an array assignment. So the following fixes this, but still joins on empty string rather than on space in the case of $@. There's probably a better way to turn the LinkList back into an array? But if this join is done any sooner, then sorting, rcexpandparam, etc. don't happen properly. If we can figure out what to pass to sepjoin() in place of NULL as the second argument, to answer my question above, all Martijn's tests can pass. The first bit with ms_flags may be meaningless, I was never sure whether that needed resetting in any case. Meat is the last hunk. diff --git a/Src/subst.c b/Src/subst.c index 1c2397c..4df53bd 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3475,7 +3475,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (nojoin == 0 || sep) { val = sepjoin(aval, sep, 1); isarr = 0; - ms_flags = 0; } else if (force_split && (spsep || nojoin == 2 || (!ifs && isarr < 0))) { /* Hack to simulate splitting individual elements: @@ -3485,6 +3484,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, val = sepjoin(aval, (nojoin == 1 ? NULL : spsep), 1); isarr = 0; } + if (!isarr) + ms_flags = 0; } if (force_split && !isarr) { aval = sepsplit(val, spsep, 0, 1); @@ -4007,6 +4008,18 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, y = dupstring(nulstring); setdata(n, (void *) y); } + if (isarr && ssub) { + /* prefork() wants a scalar, so join no matter what else */ + LinkNode tn; + + aval = hlinklist2array(l, 0); + val = sepjoin(aval, NULL, 1); + n = firstnode(l); + for (tn = lastnode(l); tn && tn != n; tn = lastnode(l)) + uremnode(l, tn); + setdata(n, (void *) val); + l->list.flags &= ~LF_ARRAY; + } if (eval) *str = (char *) getdata(n); ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS 2017-02-20 18:58 ` Bart Schaefer @ 2017-02-20 21:20 ` Bart Schaefer 2017-02-20 22:13 ` Martijn Dekker 0 siblings, 1 reply; 6+ messages in thread From: Bart Schaefer @ 2017-02-20 21:20 UTC (permalink / raw) To: Zsh hackers list On Feb 20, 10:58am, Bart Schaefer wrote: } } >--- null IFS, native splitting --- } >> var=$@ } >[one two three four] } >> var=$* } >[onetwo threefour] } >> var="$@" } >[one two three four] } >> var="$*" } >[onetwo threefour] } } Joining the array for assignment is forced by prefork() passing } PREFORK_SINGLE down to paramsubst(). Joining is supposed to be done on } the first character of $IFS in this case. When IFS is null (as opposed } to unset), this causes both $@ and $* to join on empty string. } } Where is the space supposed to come from when joining $@ here? Thanks to Chet Ramey for pointing me at http://austingroupbugs.net/view.php?id=888 Which says (very last block of examples) that var=$@ and var="$@" and a whole slew of their variations, have unspecified behavior. Consequently I'm going to take the position that zsh is allowed to join these with empty string rather than pulling a field separator out of its proverbial hat, and I will tweak 40565 appropriately and commit. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS 2017-02-20 21:20 ` Bart Schaefer @ 2017-02-20 22:13 ` Martijn Dekker 0 siblings, 0 replies; 6+ messages in thread From: Martijn Dekker @ 2017-02-20 22:13 UTC (permalink / raw) To: Zsh hackers list Op 20-02-17 om 22:20 schreef Bart Schaefer: > Thanks to Chet Ramey for pointing me at > http://austingroupbugs.net/view.php?id=888 > > Which says (very last block of examples) that var=$@ and var="$@" and > a whole slew of their variations, have unspecified behavior. True. I should not have included that in the test case. It makes sense for var=$@ and var="$@" to be unspecified. In a pure POSIX context these does not make sense, because POSIX does not have arrays, and we've already got $* to combine the PPs into a scalar. But for zsh or bash, which do have arrays, it could actually make sense to make var=$@ and var="$@" properly equivalent to var=("$@"). It's just that no shell currently does this, at least not intentionally; zsh's current behaviour as reported was clearly not consistent. > Consequently I'm going to take the position that zsh is allowed to join > these with empty string rather than pulling a field separator out of > its proverbial hat, and I will tweak 40565 appropriately and commit. Thanks. - M. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-02-20 22:13 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-02-16 23:05 [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS Martijn Dekker 2017-02-17 0:07 ` Martijn Dekker 2017-02-17 5:14 ` Bart Schaefer 2017-02-20 18:58 ` Bart Schaefer 2017-02-20 21:20 ` Bart Schaefer 2017-02-20 22:13 ` Martijn Dekker
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).