Re: [PATCH] fix "Illegal number" on FreeBSD & macOS for x=; echo $((x))

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 3/6/18 12:23 AM, Martijn Dekker wrote:
Op 05-03-18 om 22:41 schreef Harald van Dijk:
On 3/5/18 1:32 AM, Martijn Dekker wrote:
dash compiled on Mac OS X (macOS) and FreeBSD manifests the following
bug:

$ dash -c 'x=; echo $((x))'
dash: 1: Illegal number:

This error is printed instead of the expected default "0" that should be
substituted for an empty variable in an arithmetic expression.

The bug does not occur on Linux, NetBSD, OpenBSD or Solaris.

There is no reason why dash should behave differently on FreeBSD vs.
Linux, so I agree with your patch, but isn't this non-standard, isn't
either behaviour allowed?

I don't think so.

2.6.4 Arithmetic Expansion:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04
"The arithmetic expression shall be processed according to the rules
given in Arithmetic Precision and Operations [...]".

Arithmetic Precision and Operations:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_01_02_01
"All variables shall be initialized to zero if they are not otherwise
assigned by the input to the application."

In your example, x has been assigned. Its value is empty, but empty and unset are two different things.

But I see now that dash gives the same error when x is unset. That part is definitely wrong for exactly the reason you point out.

Also, consensus among existing shells appears to be universal.

Mostly, but not fully. yash is the exception:

  $ yash -c 'unset x; echo $((x))'
  0
  $ yash -c 'x=; echo $((x))'


yash is pretty special when it comes to shell arithmetic:

  $ yash -c 'x=abc; echo $((x))'
  abc
  $ yash -c 'x=abc; echo $((x+0))'
  yash: arithmetic: `abc' is not a valid number

This looks good, it does the job, but it can be simplified a bit:

If errno == EINVAL, then p == s is already known.

If errno != 0 && p == s, then errno == EINVAL is already known.

This allows simplifying to either of the following:

   if (errno != 0 && errno != EINVAL)
   if (errno != 0 && p != s)

Good point.

But perhaps

   if (errno == ERANGE)

is all that's needed here.

Explain?

Since base is always a constant 0 or a constant 10, never a user-provided value, the only error that strtoimax will ever report on glibc systems is ERANGE. Checking only ERANGE therefore preserves the glibc behaviour, and allows the exact same set of errors to be detected on non-glibc systems.

Cheers,
Harald van Dijk

Thanks,

- M.

--
To unsubscribe from this list: send the line "unsubscribe dash" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

  Powered by Linux