Subject: Re: bug#23222: test: incorrect operator-precedence

From: Eric Blake <[email-masked]>
Date: Tue, 5 Apr 2016 09:09:40 -0600

tag 23222 confirmed
thanks

On 04/05/2016 05:57 AM, Mattias Andrée wrote:
> Failing test-case #1:
> 
> ./test -n -a -n
> 
> fails and outputs
> 
>   ./test: extra argument ‘-n’
> 
> Expected behaviour is silent success, as seen in
> Bash's implementation.

Thanks for the report.  POSIX indeed says that -a is a binary primary,
and also says that
"3 arguments:
        If $2 is a binary primary, perform the binary test of $1 and $3."
(http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html)

So by that reading, coreutils MUST parse your expression as:

test \( -n \) -a \( -n \)

whereas it appears that coreutils has instead accidentally parsed it as:

test \( -n -a \) -n

Not everyday someone finds a real bug in 'test'!

That said, POSIX _also_ says that portable scripts MUST NOT use -a or
-o; it is inherently ambiguous.

You are better off fixing your script to use:

test -n && test -n

whether or not someone is able to quickly patch coreutils' bug.

> 
> Explanation: -a has higher precedence than -n.

Not quite true.  The POSIX rules state that -a is optional (non-XSI
systems don't even have to have it), and that precedence has no bearing
(rather, it is whether you have exactly three arguments that determines
whether -a must be used in its role as a binary operator).

> 
> Failing test-case #2:
> 
> ./test ! '' -a ''
> 
> shall fail (exit value 1), but in this
> implementation it succeeds.

Sorry, but here, you're wrong.  POSIX states:

"4 arguments:
        If $1 is '!', negate the three-argument test of $2, $3, and $4."

which means this parses as:

test ! \( '' -a '' \)

or as:

test ! \( \( '' \) -a \( '' \) \)

The negation of 'false and false' is true, so the exit status is
correctly 0.

> 
> Explanation: ! has higher precedence than -a,

Wrong.  As mentioned above, the rules are based not on precedence, but
on how many operands are present.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org