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?
dash on Linux also accepts 'x=\ ; echo $((x))' to print 0, and your patch also lets that work on FreeBSD.
I traced the problem to the fact that strtoimax(3) on macOS and FreeBSD returns EINVAL in errno for an empty string -- unlike those other systems, which return 0 in errno for an empty string. POSIX says of strtoimax(3): http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtoimax.html | These functions may fail if: | | [EINVAL] | No conversion could be performed. It seems reasonable to consider that "no conversion could be performed" if the string to convert is empty. Returning EINVAL if no conversion could be performed is optional ("may fail"). So it seems to me that both the FreeBSD/macOS behaviour and that of the other systems is POSIX compliant. The following patch should eliminate the bug on FreeBSD, macOS and any other POSIX system which may act the same, without affecting behaviour on other systems. - M. diff --git a/src/mystring.c b/src/mystring.c index 0106bd2..c7df41f 100644 --- a/src/mystring.c +++ b/src/mystring.c @@ -125,7 +125,7 @@ intmax_t atomax(const char *s, int base) errno = 0; r = strtoimax(s, &p, base); - if (errno != 0) + if (errno != 0 && !(errno == EINVAL && p == s))
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) But perhaps if (errno == ERANGE) is all that's needed here. Cheers, Harald van Dijk
badnum(s); /*
-- 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