zsh-workers
 help / color / mirror / code / Atom feed
From: Martijn Dekker <martijn@inlv.org>
To: zsh-workers@zsh.org
Cc: Robert Elz <kre@munnari.OZ.AU>
Subject: The big kre zsh bug report
Date: Thu, 20 Dec 2018 22:25:12 +0000	[thread overview]
Message-ID: <18f684a8-2fec-4ebe-a63e-cf6688ae519f@inlv.org> (raw)
In-Reply-To: <b8851c3a50bd8bceba1961f2f764e1a6869481ac.camel@ntlworld.com>

Robert Elz a.k.a. kre (author of NetBSD sh) ran "zsh-5.6.2 --emulate sh" 
against his NetBSD sh test suite and came up with a laundry list of test 
failures which he wanted to filter through me. Here are the ones I could 
reproduce in zsh-5.6.2-test-2 and which seemed like bugs to me.

I've ommitted test failures that clearly represent legit zsh extensions, 
such as empty command lists, arithmetic expressions in lieu of numeric 
arguments to builtins, or zsh-specific parameter expansions. At least I 
don't *think* it is the aim of sh/ksh/bash emulation mode to disable all 
zsh extensions -- just those that would cause incompatibilities.

_____________________
First, kre noted that things like $(( x )), $(( x+=1 )), and the like 
don't error out if 'set -u' (-o nounset) is active. I don't think that's 
technically a bug, because 'set -u' is specified to apply to parameter 
expansion and not arithmetic expansion. (Note that $(( $x )) contains a 
parameter expansion and 'set -u' works as expected.)

However, I think having 'set -u' apply to $(( x )) is "obvious" and 
useful behaviour. Bash, ksh93, dash, FreeBSD sh and NetBSD sh already do 
it (mksh and yash don't). I can't think of any downside so this 
behaviour. So perhaps this could be considered a feature request.

All further quoted text below is from kre... (Note his test suite output 
doesn't quote the '-c' option argument, but the tests are executed as if 
it were quoted with single quotes.)

Op 07-12-18 om 11:39 schreef Robert Elz:
> Next, for something different:
> 
> tc-so:Executing command [ zsh --emulate sh -c sleep 1 & P=$!; jobs; wait ]
> tc-se:Fail: regexp Running not in stdout
> tc-se:[1]  + running    sleep 1
> 
> Posix says of the "jobs" command that the status is Running (with a capital R)
> not "running" with a lower case 'r'.    (Same with Done, ...)

Confirmed. (Note this applies to the POSIX locale.)
Ref.: 
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/jobs.html#tag_20_62_10

_____________________
> Next:
> 
> tc-so:Executing command [ zsh --emulate sh -c for op in + - \* / %
> tc-so:            do
> tc-so:                echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
> tc-so:            done ]
> tc-se:Fail: incorrect exit status: 1, expected: 0
> tc-se:stdout:
> tc-se:11
> tc-se:
> tc-se:stderr:
> tc-se:zsh:3: bad math expression: operator expected at `2 '
> tc-se:
> 
> I am not sure what happened with that one.   zsh did do...
> 
> tc-so:Executing command [ zsh --emulate sh -c echo $(( $( echo 3 ) $( echo + ) $
> ( echo 4 ) )) ]
> 
> correctly, so it can handle expansions inside a $(( )) - perhaps the "${op}"
> being quoted confused it, but those quotes are inside $( ) and will not survive
> the result of that expansion (they are removed before echo runs), so should
> be invisible to the arith code.   They are needed so the '*' is not subject to
> filename expansion in the case when op=\*

Yes, I don't think the "${op}" being quoted has anything to do with it. 
It fails only at the second loop iteration, so with '-' as the operator.

So it doesn't like this:

$ zsh --emulate sh -c 'echo $(( $(echo 9) $(echo -) $(echo 2) ))'
zsh:1: bad math expression: operator expected at `2 '
$ zsh --emulate sh -c 'echo $(( 9 `echo -` 2 ))'
zsh:1: bad math expression: operator expected at `2 '

Whereas these works fine:

$ zsh --emulate sh -c 'echo $(( $(echo 9) - $(echo 2) ))'
7
$ zsh --emulate sh -c 'echo $(( 9 $(echo +) 2 ))'
11
$ zsh --emulate sh -c 'echo $(( 9 $(echo \*) 2 ))'
18
$ zsh --emulate sh -c 'echo $(( 9 `echo /` 2 ))'
4

So yes, that's a bug; the '-' operator is somehow handled differently 
from the rest.

_____________________
> This next one is (smilar to) the one you (Martijn) reported wrt
> the NetBSD shell just recently (one of the new tests I added
> when I fixed it...)
> 
> tc-so:Executing command [ zsh --emulate sh -c . ./h-f3; X=1; set -- ; delim_argv "${X+$@}" ]
> tc-se:Fail: stdout does not match expected value
> tc-se:--- /tmp/inline.Ph8gBl    2018-12-07 05:42:15.944365210 +0000
> tc-se:+++ /tmp/check.JvvNwL/stdout      2018-12-07 05:42:15.944098585 +0000
> tc-se:@@ -1 +1 @@
> tc-se:-
> tc-se:+><       
> 
> "h-f3" just contains the definition of the delim_argv function, which
> is simply...
> 
> delim_argv() {
>         str=
>         for Arg; do
>                 str="${str:+${str} }>${Arg}<"
>         done
>         printf '%s\n' "${str}"
> } 
> 
> ie: stick ><  (angle quotes, except in the backwards
> order, so they are more obvious) around each arg.
> 
> This indicates that zsh is parsing that the same way we did I
> think, and not producing nothing when there are no args from
> the (enclosed) quoted $@
> 
> The output is a diff -u with the first arg ('-' lines in output) being what
> was expected (the file with "inline" in its name) and the 2nd arg ('+'
> lines in the output) being the output from the command.

Hmm... to make this a little easier to understand and reproduce:

zsh --emulate sh -c 'delim_argv() { str=;
		for Arg do str="${str:+${str} }>${Arg}<"; done;
		printf "%s\n" "${str}"; };
	X=1; set -- ; delim_argv "${X+$@}"'

zsh, bash, dash, ksh93, mksh >= R50e, FreeBSD sh output:
 ><

yash, mksh <= R50 output nothing.

So the issue is that "${X+$@}" should be removed completely and not 
leave an empty quoted string if X is set, but there are no positional 
parameters.

Looks logical to me: in that the ${X+$@} parameter substitution 
substitutes $@, within quotes, leaving "$@", which is definitely removed 
completely if there are no positional parameters.

But if this is a bug, it's certainly a widespread one!

_____________________
> tc-se:dollar_hash[7]: Test of 'set -- a b c; echo ${\#}' failed.
> tc-se:[7] expected exit code 2, got 0
> tc-se:[7] Expected messages on stderr, nothing produced
> tc-se:[7] Expected output '', received '3' 
> tc-se:[7] Full command: <<set -- a b c; echo ${\#}>>
> 
> The \ is not removed before var expansion, ${\#} is not ${#}
> and \# is not a valid var name, nor is \ if this is being parsed
> as a substring match on ${\}  
> so this should be a syntax error
> (at least in sh emulation mode).
> 
> There is another test which fails in a similar way for the same
> reason ...
> 
> tc-se:dollar_hash[8]: Test of 'set -- a b c; echo ${\#:-foo}' failed.

Confirmed. ${\#} or ${\#:-foo} should be syntax errors, but aren't.

Same with other special parameters: ${\?}, ${\!}, etc. and even normal 
variables: ${\foo}.

_____________________
> And something different, but related, perhaps:
> 
> tc-se:dollar_hash[48]: Test of 'x=hello; set -- a b c; echo ${#x:-1}' failed.
> tc-se:[48] expected exit code 2, got 0
> tc-se:[48] Expected messages on stderr, nothing produced
> tc-se:[48] Expected output '', received '5'
> tc-se:[48] Full command: <<x=hello; set -- a b c; echo ${#x:-1}>>
> 
> Combining length and set/not set operators is not defined in sh,
> and makes no sense anyway, as ${#x} is always set (it is a number,
> 0 .. whatever, so cannot be unset or null - if 'x' is unset and -u
> is on, there might be an error, but returning the length of $x with
> this nonsense syntax is always incorrect).
> 
> And more like that one ...
> 
> tc-se:dollar_hash[49]: Test of 'x=hello; set -- a b c; echo ${#x-1}' failed.
> tc-se:dollar_hash[50]: Test of 'x=hello; set -- a b c; echo ${#x:+1}' failed.
> tc-se:dollar_hash[51]: Test of 'x=hello; set -- a b c; echo ${#x+1}' failed.
> tc-se:dollar_hash[52]: Test of 'x=hello; set -- a b c; echo ${#x+1}' failed.
> tc-se:dollar_hash[53]: Test of 'x=hello; set -- a b c; echo ${#x:?msg}' failed.
> tc-se:dollar_hash[54]: Test of 'x=hello; set -- a b c; echo ${#x?msg}' failed.
> tc-se:dollar_hash[55]: Test of 'x=hello; set -- a b c; echo ${#x:=val}' failed.
> tc-se:dollar_hash[56]: Test of 'x=hello; set -- a b c; echo ${#x=val}' failed.
> tc-se:dollar_hash[57]: Test of 'x=hello; set -- a b c; echo ${#x#h}' failed.
> tc-se:dollar_hash[58]: Test of 'x=hello; set -- a b c; echo ${#x#*l}' failed.
> tc-se:dollar_hash[59]: Test of 'x=hello; set -- a b c; echo ${#x##*l}' failed.
> tc-se:dollar_hash[60]: Test of 'x=hello; set -- a b c; echo ${#x%o}' failed.
> tc-se:dollar_hash[61]: Test of 'x=hello; set -- a b c; echo ${#x%l*}' failed.
> tc-se:dollar_hash[62]: Test of 'x=hello; set -- a b c; echo ${#x%%l*}' failed.

I'll leave this for the zsh developers to consider, but personally I 
think we can legitimately consider this an artefact of a zsh extension.

Zsh has always allowed combining things in parameter substitutions that 
other shells don't, and allowing nonsensical combinations is simply a 
side effect of allowing other, sensible ones. Zsh accepting something 
other POSIX shells don't, even in emulation mode, will not cause any 
compatibility problems as long as POSIX syntax is followed.

As far as I know, no shell except yash aims to prohibit everything not 
allowed by POSIX in its POSIX compatibility mode. (IOW, for a strict 
POSIX compatibility test, I'd highly recommend 'yash -o posix'!)

_____________________
> Next we get similar tests, but this time we are testing $# rather than the
> length of a var operator...
> 
> tc-se:dollar_hash[79]: Test of 'set -- a b c; echo ${#:-99}' failed.
> tc-se:[79] Expected output '3', received '2'
> tc-se:[79] Full command: <<set -- a b c; echo ${#:-99}>>
> 
> For $# I am not sure posix requires handling the tests for set/unset
> (as $# is always set) so I would understand an error here, but not
> the wrong answer, there are 3 args $# should be 3, it is never unset
> or null, so the :-99 part should just be noise (or an error).

Confirmed:

$ zsh --emulate sh -c 'set -- a b c; echo ${#:-99}'
2

That should be 3, so this is a bug.

Hmmm...

$ zsh --emulate sh -c 'set -- a b c; echo ${#}'
3
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-}'
0
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-3}'
1
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-3000}'
4
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-10chstring}'
10
$ zsh --emulate sh -c 'bar=10chstring; set -- a b c; echo ${#:-$bar}'
10

So what happens is that ${#:-foo} measures the length of whatever 
follows ':-'. Interesting behaviour, but not correct, at least not for 
POSIX mode.

_____________________
> This next one does generate an error from zsh, which is not
> unreasonable:
> 
> tc-se:dollar_hash[80]: Test of 'set -- a b c; echo ${#-99}' failed.
> tc-se:[80] expected exit code 0, got 1
> tc-se:[80] Messages produced on stderr unexpected...
> tc-se:zsh:1: bad substitution
> tc-se:[80] Expected output '3', received ''
> tc-se:[80] Full command: <<set -- a b c; echo ${#-99}>>
> 
> so why it acted differently when the ':' was there is hard to explain.

I think it's a (minor) bug. Since $# is always set, ${#-foo} should be 
accepted as equivalent to $#.

> I see them same (not really incorrect, this is in "unspecified" territory
> I think ... our tests test NetBSD sh behaviour)...
> 
> tc-se:dollar_hash[84]: Test of 'set -- a b c; echo ${#?bogus}' failed.
> tc-se:[84] expected exit code 0, got 1
> tc-se:[84] Messages produced on stderr unexpected...
> tc-se:zsh:1: bad substitution
> tc-se:[84] Expected output '3', received ''
> tc-se:[84] Full command: <<set -- a b c; echo ${#?bogus}>>

IMHO, same as above: $# is always set, so ${#?bogus} should be accepted 
as equivalent to $#.

_____________________
> This next one is an obvious, and common, problem ...
> 
> tc-se:shell_params[13]: Test of 'set -- a b c d; echo ${4294967297}' failed.
> tc-se:[13] Expected output '', received 'a'
> tc-se:[13] Full command: <<set -- a b c d; echo ${4294967297}>>
> 
> (4294967297 & 0xFFFFFFFF) == 1
> 
> This indicates that 32 bit arith overflow occurred, and wasn't detected.

Confirmed (also on ksh93 and dash).

_____________________
> This next one indicates that \newline line joining is not working correctly
> I think ...
> 
> tc-so:Executing command [ zsh --emulate sh -c line='#define bindir "/usr/bin" /* comment */'; echo :"$\
> tc-so:{li\
> tc-so:ne%\
> tc-so:'/*'*}": ] 
> tc-se:Fail: stdout does not match expected value
> tc-se:--- /tmp/inline.FL7wVx    2018-12-07 05:42:17.365040418 +0000
> tc-se:+++ /tmp/check.5PcEmx/stdout      2018-12-07 05:42:17.364785460 +0000
> tc-se:@@ -1 +1 @@
> tc-se:-:#define bindir "/usr/bin" :
> tc-se:+:{line%'/*'*}:   
> 
> Since the previous test ...
> 
> tc-so:Executing command [ zsh --emulate sh -c line='#define bindir "/usr/bin" /* comment */'; echo :${line\
> tc-so:%\
> tc-so:'/*'*}: ]  
> 
> does work, and it should end up being the exact same thing, my guess is
> that the ${ with a \newline between the $ and { is not working as it should.

Confirmed. A bit more experimenting shows that it breaks between '$' and 
'{' and nowhere else. Very unlikely for line continuation to be used 
there in real-life scripts, but still a bug.

$ zsh --emulate sh -c 'foo=bar; echo $\
foo'
bar
$ zsh --emulate sh -c 'foo=bar; echo $\
{foo}'
{foo}
$ zsh -c 'line='\''#define bindir "/usr/bin" /* comment */'\''; echo 
:"${\
l\
i\
n\
e\
%\
'\''\
/\
*\
'\''\
*\
}\
"\
:'
:#define bindir "/usr/bin" :

_____________________
> Next ...
> 
> 	check 't=" x";     IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1'
> 
> The first arg to "check" is evaluated using ${SHELL} -c the 2nd arg is the
> expected output....    This one is test 2 of the IFS tests (test 1 
> passed).
> 
> tc-end: 1544161337.630429, ifs, failed, Test 2 't=" x";     ...': expected [1], found [2 :]
> 
> (unfortunately here, when it fails, the "check" in question truncates the
> command in the message, it is expected you will look at the test source
> to see what it really was.... so I am including the ones that fail.   I should
> improve the output from this "check" function - this was an early version...
> 
> The data enclosed in [] is what should have been output. and what
> actually was.
> 
> I think this means that zsh is not treating non-whitespace IFS characters
> as field terminators, but as field separators, which is not the way it is
> supposed to be.  A later failure is because of the same thing I believe.

Confirmed. Modernish identifies this as a shell quirk (QRK_IFSFINAL) 
because the POSIX spec is quite ambiguous on this, so I was unable to 
confirm that it is actually a bug and not a legitimate behaviour variant.

However, yash's author, magicant, has since decided it's a bug, and 
fixed it, adding a shell option to restore the old behaviour. See 
discussion here:
https://osdn.net/projects/yash/ticket/35283

He refers to this clarification:
http://www.open-std.org/JTC1/SC22/WG15/docs/rr/9945-2/9945-2-98.html

So this should probably be fixed, at least for sh emulation mode.

_____________________
> Next, with IFS containing a digit...
> 
>         check 'IFS=5; echo $(( 123456789 ))'    '1234 6789'
> 
> tc-end: 1544161337.819973, split_arith, failed, Test 1 'IFS=5; echo ...': expect
> ed [1234 6789], found [123456789]

This has come up before on zsh-workers. It's known that artihmetic 
expansion is not subject to field splitting in zsh and they've declined 
to fix it on the grounds that field splitting arithmetic expansions is 
nonsensical. I would prefer consistent field splitting of all dollar 
expansions as the standard requires, but was outgunned by Stéphane 
Chazelas. (IMHO, a more sensible use case would be to split on the 
decimal point.)

_____________________
> The next test is also perhaps dubious, and bizarre, but ...
> 
>         check 'cat <<  echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" 'echo' 0
> 
> ($nl is a single newline character).
> 
> tc-se:lineends[2]: test of 'cat <<  echo
> tc-se:\
> tc-se:echo
> tc-se:echo
> tc-se:' failed
> 
> The point here is that the here doc delimiter
> is unqoted "echo", then in the here doc, the \
> on the first line joins the 2nd line to it, which
> as I read the spec, means it cannot be the
> terminator of the here doc, no matter what it
> ends up containing, as that is required to be
> on a line containing nothing else (after leading
> tabs are stripped if appropriate, which isn't the
> case here, and there aren't any anyway).  If
> a line has been joined to a previous line, I interpret
> that as meaning it cannot be the terminator (and
> allowing it to be adds nothing useful to the shell,
> other than the potential for errors).
> 
> Hence, I believe in this that "echo" is the correct
> output.    But if the first "echo" terminates, we get
> no output (as trailing newlines get removed by
> the command substitution that "check" uses to
> capture the results, so the missing \n from the
> echo command that would follow makes sense).
> 
> But this is a view of how here docs work that is
> not necessarily agreed by all...

Your interpretation looks correct to me, but few real-life shells follow 
it (dash, recent yash, and ksh93 are the ones I can quickly identify).

_____________________
> Next, zsh apparently does not implement the posix
> required -h option.   Nor do we, but we at least allow
> it to be set and cleared ....

I'm not sure that allowing it to be set and then not doing what it 
promises is better than not allowing it to be set at all.

_____________________
> Next onto pattern tests ...
> 
> tc-se:case_matching[51]: Test of 'case "[a-c]" in ([a-c\]) printf M;; (*) printf X;; esac' failed.
> tc-se:[51] Messages produced on stderr unexpected...
> tc-se:zsh:1: bad pattern: [a-c]
> tc-se:[51] Expected output 'M', received ''
> tc-se:[51] Full command: <<case "[a-c]" in ([a-c\]) printf M;; (*) printf X;; esac>>
> 
> There is no such thing as a "bad pattern" in sh - there is no
> [xyz] expression there, because of the quoted ']' (so there is
> no terminator) which means the '[' is just a character, so this
> pattern is effectively just "[a-c]" which should match the word
> which is the same thing.
> 
> It works when the [ is quoted ( \[a-c] ), or when the whole thing is ( "[a-c]" ).

[...and, moved up here from later in the original email...]
> tc-se:var_substring_matching[94]: Test of 'var='[a-c]d-f';printf '%s\n' ${var#[a-c\]}' failed.
> tc-se:[94] expected exit code 0, got 1
> tc-se:[94] Messages produced on stderr unexpected...
> tc-se:zsh:1: bad pattern: [a-c]
> tc-se:[94] Expected output 'd-f', received ''
> tc-se:[94] Full command: <<var='[a-c]d-f';printf '%s\n' ${var#[a-c\]}>>
> 
> This is the same issue as the earlier 'case' matching problem.
> There are no bad patterns in sh.   Ever.   The literal string
> '[a-c]' should be removed from the start of the value of var.

Properly quoted test cases:

$ zsh --emulate sh -c 'case "[a-c]" in ([a-c\]) printf M;;
	(*) printf X;; esac'
$ zsh --emulate sh -c "var='[a-c]d-f';printf '%s\\n' \${var#[a-c\\]}"

Confirmed. The first test case works on all shells except zsh. For the 
second, it works on all except zsh, ksh93 and mksh; the latter two don't 
throw an error, but fail to remove the '[a-c]'.

_____________________
> tc-se:case_matching[90]: Test of 'case a in ([[\:alpha:]]) printf M;; (*) printf X;; esac' failed.
> tc-se:[90] Expected output 'X', received 'M'
> tc-se:[90] Full command: <<case a in ([[\:alpha:]]) printf M;; (*) printf X;; esac>>
> 
> Here the quoted ':' means there is no char-class, so what is
> left is a simple [xyz] expression, where the xyz part is "[\:alpha:"
> the following ']' terminates that expression, and the ']' that
> follows it is just a character.   The 'a' matches the [...] (which
> contains an 'a') but there is nothing in the word to match that
> extra ']', so the match should fail.
> 
> tc-se:case_matching[96]: Test of 'var=":alpha:"; case B in ([["$var"]]) printf M;; (*) printf X;; esac' failed.
> tc-se:[96] Expected output 'X', received 'M'
> tc-se:[96] Full command: <<var=":alpha:"; case B in ([["$var"]]) printf M;; (*) printf X;; esac>>
> 
> This is similar. the : is quoted (via quoted $var) so there is no
> char class, 
> just a [] expression followed by a stray ']'
> 
> tc-se:case_matching[98]: Test of 'var=":alpha:"; case "[]" in ([["$var"]]) printf M;; (*) printf X;; esac' failed.
> tc-se:[98] Expected output 'M', received 'X'
> tc-se:[98] Full command: <<var=":alpha:"; case "[]" in ([["$var"]]) printf M;; (*) printf X;; esac>>
> 
> This is the same thing, buit in a "should match" scenario, the [
> in the word is matched by the [xyz] expression, which contains a '['
> (for the same reason as the last two) and the ] in the word matches
> the trailing ] that comes after the [xyz] expression, and we have a match.

Yes, that looks like three ways of testing the same thing.

Shells differ here. bash, dash, mksh<=R55 print X on the first and 
second, M on the third; yash, ksh93, mksh>=R56c, zsh print M on the 
first and second, X on the third.

_____________________
> tc-se:case_matching[147]: Test of 'var='\z'; case ${var} in (${var}) printf M;; (*) printf X;; esac' failed.
> tc-se:[147] Expected output 'X', received 'M'
> tc-se:[147] Full command: <<var='\z'; case ${var} in (${var}) printf M;; (*) printf X;; esac>>
> 
> The word to match is two chars, backslash and z, the pattern is
> a quoted 'z' (the backslash becomes a quoting character).   After
> that happens, there is nothing magic in the pattern, just one literal
> char, 2 chars can never match 1, so it should fail.

Properly quoted test case:

$ zsh --emulate sh -c 'var='\''\z'\'';
	case ${var} in (${var}) printf M;; (*) printf X;; esac'

This outputs X on bash, dash, ksh93, and M on yash, mksh, zsh.

This issue caused me headaches when implementing match() on modernish. I 
was given the impression that passing backslash-quoted characters 
through variables for use in 'case' patterns was one of those things 
that POSIX doesn't really specify one way or another. Of course I would 
much prefer the behaviour of bash, dash, and NetBSD sh.

_____________________
> tc-se:case_matching[265]: Test of 'var='\'; case '\' in ($var) printf M;; (*) printf X;; esac' failed.
> tc-se:[265] Expected output 'X', received 'M'
> tc-se:[265] Full command: <<var='\'; case '\' in ($var) printf M;; (*) printf X;; esac>>
> 
> This one is excusable, a \ followed by nothing in a pattern is an unspecified
> case, so anything is OK, and treating it as a literal \ is reasonable (it is
> just not what we do ... it is also not what bash does, so as this one also 
> fails in bash emulation, there probably is something that needs fixing.
> 
> tc-se:case_matching[267]: Test of 'set -- \\ \\; case $1 in ($2) printf M;; (*) printf X;; esac' failed.
> tc-se:[267] Expected output 'X', received 'M'
> tc-se:[267] Full command: <<set -- \\ \\; case $1 in ($2) printf M;; (*) printf X;; esac>>
> 
> This one is the same, both pattern and word are '\'  just created
> in a different way.
> 
> tc-se:case_matching[271]: Test of 'case '\' in ($( echo '\' )) printf M;; (*) printf X;; esac' failed.
> tc-se:[271] Expected output 'X', received 'M'
> tc-se:[271] Full command: <<case '\' in ($( echo '\' )) printf M;; (*) printf X;; esac>>
> 
> That one too.   Note all 3 of them work the same in bash as we expect,
> and all 3 still fail with zsh --emulate bash

I'm not sure the zsh authors aim to make emulation modes quite that 
exact, but I'll just leave this here for their consideration.

_____________________
> tc-se:var_substring_matching[47]: Test of 'var='abc';printf '%s\n' ${var%*}' failed.
> tc-se:[47] Expected output 'abc', received 'ab'
> tc-se:[47] Full command: <<var='abc';printf '%s\n' ${var%*}>>
> 
> This one is easy, * should start out matching nothing, that matches, so
> nothing should be removed from the value.   zsh is removing 'c'.
> (Yes, it is a stupid thing to do, or to expect to work, but it is how it
> is supposed to function.)
> 
> tc-se:var_substring_matching[48]: Test of 'var='abc';printf '%s\n' "${var%*}"' failed.
> tc-se:[48] Expected output 'abc', received 'ab'
> tc-se:[48] Full command: <<var='abc';printf '%s\n' "${var%*}">>
> 
> That is the same, just in a quoted expansion (should change nothing).

Properly quoted test cases:

$ zsh --emulate sh -c "var='abc';printf '%s\\n' \${var%*}"
$ zsh --emulate sh -c "var='abc';printf '%s\\n' \"\${var%*}\""

Bug confirmed; every shell except zsh prints 'abc'.

_____________________
Various other tests showed that zsh cannot handle file descriptors >9. 
Not really a bug as POSIX permits that limitation, but:

> And again, this test fails the same way with --emulate bash
> and bash certainly permits fds > 9!

So you could consider this a feature request.

_____________________
> tc-so:Executing command [ zsh --emulate sh -c  set -- a b c d; shift 1 1 ; echo FAILED  ]
> tc-se:Fail: incorrect exit status: 0, expected: anything else
> tc-se:stdout:
> tc-se:FAILED
> tc-se:
> tc-se:stderr:
> tc-se:
> 
> shift should only take 1 arg, not two ... but most shells do not check that,
> so this one is perhaps excusable.

I think builtins should always fail on excess arguments since, outside 
of test cases, that is a clear indication something has gone awry in the 
script.

_____________________
> In this one zsh is generating a syntax error, when there is none...
> 
> tc-so:Executing command [ zsh --emulate sh -c echo hello; true&false&:&cat</dev/null>/dev/null&x=3& echo world ]
> tc-se:Fail: incorrect exit status: 1, expected: 0
> tc-se:stdout:
> tc-se:
> tc-se:stderr:
> tc-se:zsh:1: parse error near `&'
> tc-se:
> 
> Which of the numerous '&' chars it does not like I have no idea.

Looks like zsh doesn't like a bare shell assignment as a background job.

$ zsh --emulate sh -c 'x=3 &'
zsh:1: parse error near `&'

Pointless or not, this is a bug. All other shells accept this.

_____________________
> tc-so:Executing command [ zsh --emulate sh -c case in in (esac|cat ]
> tc-se:Fail: incorrect exit status: 0, expected: anything else
> tc-se:stdout:
> tc-se:
> tc-se:stderr:
> tc-se:
> 
> I cannot even begin to imagine what that nonsense parsed as...
> (but once a case pattern is started with the optional '(' it requires
> the following ')' to complete it, always.

Probably related to zsh accepting empty command lists in all sorts of 
contexts where other shells don't. But it still seems strange that it 
accepts this:

$ zsh --emulate sh -c 'case in in (esac'
(no syntax error produced)

_____________________
> And another one that zsh cannot parse, though again, this one
> is legal...
> 
> tc-so:Executing command [ zsh --emulate sh -c if if :;then :;fi then :;fi ]
> tc-se:Fail: incorrect exit status: 1, expected: 0
> tc-se:stdout:
> tc-se:
> tc-se:stderr:
> tc-se:zsh:1: parse error near `then'
> tc-se:
> 
> I would guess it is the second "then" that follows "fi" with no ';'
> that is the problem, but that is OK syntax.

I would not have thought that to be correct syntax, but sure enough, 
every shell except zsh accepts it.

A similar case (with another reserved word, 'esac', directly preceding 
'then') works fine:

$ zsh --emulate sh -c 'if case a in a) ;; esac then :; fi'
(no syntax error produced)

However, this one fails on zsh and works on all other shells:

$ zsh --emulate sh -c 'if until :; do :; done then :; fi'
zsh:1: parse error near `then'

_____________________
> tc-so:Executing command [ zsh --emulate sh -c case x in (|| | ||) ;; esac ]
> tc-se:Fail: incorrect exit status: 0, expected: anything else
> tc-se:stdout:
> tc-se:
> tc-se:stderr:
> tc-se:
> 
> Not sure what I should say about that one... (but patterns are not
> allowed to be completely missing, there must be a word, and lots
> of alternative illegal missing patterns does not make it legal).

This was a syntax error in zsh until 5.4.1; 5.4.2 starts accepting it.

Strangely, dash accepts this.

_____________________
> There is a failure of a test testing %n notation for jobs in wait commands,
> but I need to check that one more carefully before complaining about it
> failing, it may be that the test is technically invalid (ie: that zsh is
> permitted to act as it does) but this next one ...
> 
> tc-so:Executing command [ zsh --emulate sh -c wait 1 ]
> tc-se:Fail: incorrect exit status: 1, expected: 127
> tc-se:stdout:
> tc-se:
> tc-se:stderr:
> tc-se:zsh:wait:1: pid 1 is not a child of this shell
> tc-se:
> 
> is clearly wrong.  The error message is maybe OK (it is
> correct, though I don't think "wait" is supposed to issue it)
> but the exit status is clearly wrong, wait is required to return
> status 127 when the given pid is not a child, not 1.

Bug confirmed:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/wait.html#tag_20_153_14

ksh93 returns status 0, which is even more wrong! All other shells 
except zsh return status 127.

_____________________

That's it. Hope this is useful!

- M.

       reply	other threads:[~2018-12-20 22:49 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <d7b0451f90bdfe61f48cc1361690180e07158900.camel@ntlworld.com>
     [not found] ` <b8851c3a50bd8bceba1961f2f764e1a6869481ac.camel@ntlworld.com>
2018-12-20 22:25   ` Martijn Dekker [this message]
2018-12-21  7:53     ` Bart Schaefer
2018-12-21  8:11       ` Fix for ${\var} oddity Bart Schaefer
2018-12-25 17:18       ` [PATCH] honour NO_UNSET when reading values in arithmetic expansion/commands Martijn Dekker
2018-12-25 20:44       ` 'wait' exit status and warnings [was: The big kre zsh bug report] Martijn Dekker
2018-12-30 18:13         ` Peter Stephenson
2019-01-21 22:53           ` Martijn Dekker
2018-12-31  2:08       ` Line continuation between $ and { " Martijn Dekker
2018-12-21 11:30     ` The big kre zsh bug report Robert Elz
2018-12-21 20:37       ` Bart Schaefer
2018-12-22  0:13       ` Robert Elz
2018-12-21  2:28   ` Robert Elz
2018-12-24  5:40 ` zsh 5.6.2-test-2 Axel Beckert
2018-12-24  7:14   ` Axel Beckert
2018-12-24  7:38     ` dana
2018-12-24  9:16       ` [PATCH] ztrftime(): Fix truncation for % dana
2018-12-24 12:45         ` Daniel Shahaf
2018-12-24 16:24           ` dana
2018-12-24 17:06             ` Daniel Shahaf
2018-12-24 17:31               ` dana
2018-12-28 22:16                 ` dana
2018-12-29  9:55                   ` Daniel Shahaf
2018-12-29 10:27                     ` Daniel Shahaf
2018-12-29 11:02                       ` dana
2018-12-29 11:08                         ` Daniel Shahaf
2018-12-29 11:30                           ` dana
2018-12-29 11:34                             ` Daniel Shahaf
2018-12-24 23:35           ` Joey Pabalinas
2018-12-24 23:30         ` Joey Pabalinas
     [not found] ` <CAKc7PVDUjo8HAdwqgRAKcgQHOzThM+hYnjX+2FKzUZB+pfmC-Q@mail.gmail.com>
     [not found]   ` <CAKc7PVB-agFUarJ=LqC2QNDFta1O5D_o4v-gt7LiobVDohNGVQ@mail.gmail.com>
     [not found]     ` <06228a6975b91f7066d0046bf912dd69fa5993a2.camel@ntlworld.com>
2018-12-31 13:44       ` zsh 4.6.2-test-2 dana
2018-12-31 15:19         ` Sebastian Gniazdowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=18f684a8-2fec-4ebe-a63e-cf6688ae519f@inlv.org \
    --to=martijn@inlv.org \
    --cc=kre@munnari.OZ.AU \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).